diff --git a/xpm/xpm_cdc.sv b/xpm/xpm_cdc.sv new file mode 100644 index 0000000..834a35e --- /dev/null +++ b/xpm/xpm_cdc.sv @@ -0,0 +1,1491 @@ +//------------------------------------------------------------------------------ +// (c) Copyright 2015 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. +//------------------------------------------------------------------------------ + +// *************************** +// * DO NOT MODIFY THIS FILE * +// *************************** + +`timescale 1ps/1ps + +`default_nettype none + +// ------------------------------------------------------------------------------------------------------------------- +// Macro definitions. Only to be used by xpm_cdc_* modules. +// ------------------------------------------------------------------------------------------------------------------- + +// Define Xilinx Synchronous Register. Only to be used by xpm_cdc_* modules. +`define XPM_XSRREG(clk, reset_p, q, d, rstval) \ + always @(posedge clk) begin \ + if (reset_p == 1'b1) \ + q <= rstval; \ + else \ + q <= d; \ + end + +// Define Xilinx Synchronous Register with Enable. Only to be used by xpm_cdc_* modules. +`define XPM_XSRREGEN(clk, reset_p, q, d, en, rstval) \ + always @(posedge clk) begin \ + if (reset_p == 1'b1) \ + q <= rstval; \ + else \ + if (en == 1'b1) \ + q <= d; \ + end + +// Define Xilinx Asynchronous Register. Only to be used by xpm_cdc_* modules. +`define XPM_XARREG(clk, reset_p, q, d, rstval) \ + always @(posedge clk or posedge reset_p) \ + begin \ + if (reset_p == 1'b1) \ + q <= rstval; \ + else \ + q <= d; \ + end + +//================================================================================================================== + + // Define Xilinx Synchronous Register. Only to be used by xpm_cdc_* modules. +`define XPM_XSRREG_INIT(clk, reset_p, q, d, rstval, gsr_asserted, gsr_init_val) \ + always @(gsr_asserted) begin \ + if (gsr_asserted) \ + force q = gsr_init_val; \ + else \ + release q; \ + end \ + \ + always @(posedge clk) begin \ + if (reset_p == 1'b1) \ + q <= rstval; \ + else \ + q <= d; \ + end + +// Define Xilinx Synchronous Register with Enable. Only to be used by xpm_cdc_* modules. +`define XPM_XSRREGEN_INIT(clk, reset_p, q, d, en, rstval, gsr_asserted, gsr_init_val) \ + always @(gsr_asserted) begin \ + if (gsr_asserted) \ + force q = gsr_init_val; \ + else \ + release q; \ + end \ + \ + always @(posedge clk) begin \ + if (reset_p == 1'b1) \ + q <= rstval; \ + else \ + if (en == 1'b1) \ + q <= d; \ + end + +// Define Xilinx Asynchronous Register. Only to be used by xpm_cdc_* modules. +`define XPM_XARREG_INIT(clk, reset_p, q, d, rstval, gsr_asserted, gsr_init_val) \ + always @(gsr_asserted or reset_p) \ + if (gsr_asserted) \ + force q = gsr_init_val; \ + else if (reset_p === 1'b1) \ + force q = ~gsr_init_val; \ + else if (reset_p === 1'bx) \ + force q = 1'bx; \ + else \ + release q; \ + \ + always @(posedge clk or posedge reset_p) \ + begin \ + if (reset_p == 1'b1) \ + q <= rstval; \ + else \ + q <= d; \ + end + +//******************************************************************************************************************** +//******************************************************************************************************************** +//******************************************************************************************************************** + +// ------------------------------------------------------------------------------------------------------------------- +// Single-bit Synchronizer +// ------------------------------------------------------------------------------------------------------------------- +(* XPM_MODULE = "TRUE", XPM_CDC = "SINGLE", KEEP_HIERARCHY = "TRUE" *) +module xpm_cdc_single #( + // Module parameters + parameter integer DEST_SYNC_FF = 4, + parameter integer INIT_SYNC_FF = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer SRC_INPUT_REG = 1, + parameter integer VERSION = 0 +) ( + // Module ports + input wire src_clk, + input wire src_in, + input wire dest_clk, + output wire dest_out +); + + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ------------------------------------------------------------------------------------------------------------------- + initial begin : config_drc_single + reg drc_err_flag; + drc_err_flag = 0; + + if ((DEST_SYNC_FF < 2) || (DEST_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] DEST_SYNC_FF (%0d) value is outside of valid range of 2-10. %m", "XPM_CDC", 1, 2, DEST_SYNC_FF); + drc_err_flag = 1; + end + + if (!(INIT_SYNC_FF==0) && !(INIT_SYNC_FF==1)) begin + $error("[%s %0d-%0d] INIT_SYNC_FF (%0d) is outside of valid range. %m", "XPM_CDC", 1, 5, INIT_SYNC_FF); + drc_err_flag = 1; + end + + if (!(SRC_INPUT_REG == 0) && !(SRC_INPUT_REG == 1)) begin + $error("[%s %0d-%0d] SRC_INPUT_REG (%0d) value is outside of valid range. %m", "XPM_CDC", 1, 3, SRC_INPUT_REG); + drc_err_flag = 1; + end + + if (!(SIM_ASSERT_CHK==0) && !(SIM_ASSERT_CHK==1)) begin + $error("[%s %0d-%0d] SIM_ASSERT_CHK (%0d) value is outside of valid range. %m", "XPM_CDC", 1, 4, SIM_ASSERT_CHK); + drc_err_flag = 1; + end + + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of valid range. %m", "XPM_CDC", 1, 1, VERSION); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + end : config_drc_single + + // Set Asynchronous Register property on synchronizers + (* XPM_CDC = "SINGLE", ASYNC_REG = "TRUE" *) reg [DEST_SYNC_FF-1:0] syncstages_ff; + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation only variable and signal assignment + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + `ifndef ONESPIN + `define XPM_CDC_BHVSIM_ONLY + tri0 glblGSR_xpmcdc = glbl.GSR; + `endif + // synthesis translate_on + + reg src_ff; + wire src_inqual; + wire async_path_bit; + + assign dest_out = syncstages_ff[DEST_SYNC_FF-1]; + assign async_path_bit = src_inqual; + + // Virtual mux: Register at input optional. + generate + if (SRC_INPUT_REG) begin : extra_inreg + assign src_inqual = src_ff; + end : extra_inreg + else begin : no_extra_inreg + assign src_inqual = src_in; + end : no_extra_inreg + endgenerate + + // Instantiate Xilinx Synchronous Register + `ifdef XPM_CDC_BHVSIM_ONLY + if(INIT_SYNC_FF) begin + `XPM_XSRREG_INIT(src_clk , 1'b0, src_ff, src_in, 1'b0, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(dest_clk, 1'b0, syncstages_ff, { syncstages_ff[DEST_SYNC_FF-2:0], async_path_bit} , {DEST_SYNC_FF{1'b0}}, glblGSR_xpmcdc, 1'b0) + end else begin + `XPM_XSRREG(src_clk , 1'b0, src_ff, src_in, 1'b0) + `XPM_XSRREG(dest_clk, 1'b0, syncstages_ff, { syncstages_ff[DEST_SYNC_FF-2:0], async_path_bit} , {DEST_SYNC_FF{1'b0}}) + end + `else + `XPM_XSRREG(src_clk , 1'b0, src_ff, src_in, 1'b0) + `XPM_XSRREG(dest_clk, 1'b0, syncstages_ff, { syncstages_ff[DEST_SYNC_FF-2:0], async_path_bit} , {DEST_SYNC_FF{1'b0}}) + `endif + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation constructs + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + + initial begin : sim_check + #1; + if (SIM_ASSERT_CHK == 1) begin : sim_xil_check + `ifdef OBSOLETE + $warning("Vivado Simulator does not currently support the SystemVerilog Assertion syntax used within XPM_CDC. \ +Messages related to potential misuse will not be reported."); + `endif + end : sim_xil_check + end : sim_check + + `ifndef OBSOLETE + //S_A1: To guarantee data is transfered into destination clock domain (asynchronous to source clock domain), input data + //must be sampled at the minimum by 2 destination clock edges. + if (SIM_ASSERT_CHK == 1) begin : min_sampling + assume property (@(posedge dest_clk) + !( $stable(src_in) ) |-> ##1 $stable(src_in) [*2]) + else + $error("[%s %s-%0d] Input data at %0t is not stable long enough to be sampled twice by the destination clock. \ +Data in source domain may not transfer to destination clock domain.", "XPM_CDC_SINGLE", "S", 1, $time); + end : min_sampling + `endif + + // synthesis translate_on + +endmodule : xpm_cdc_single + + +// ------------------------------------------------------------------------------------------------------------------- +// Binary Bus Synchronizer +// ------------------------------------------------------------------------------------------------------------------- +(* XPM_MODULE = "TRUE", XPM_CDC = "GRAY", KEEP_HIERARCHY = "TRUE" *) +module xpm_cdc_gray #( + // Module parameters + parameter integer DEST_SYNC_FF = 4, + parameter integer INIT_SYNC_FF = 0, + parameter integer REG_OUTPUT = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer SIM_LOSSLESS_GRAY_CHK = 0, + parameter integer VERSION = 0, + parameter integer WIDTH = 2 +) ( + // Module ports + input wire src_clk, + input wire [WIDTH-1:0] src_in_bin, + input wire dest_clk, + output wire [WIDTH-1:0] dest_out_bin +); + + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ------------------------------------------------------------------------------------------------------------------- + initial begin : config_drc_gray + reg drc_err_flag; + drc_err_flag = 0; + + if ((DEST_SYNC_FF < 2) || (DEST_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] DEST_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 2, 2, DEST_SYNC_FF); + drc_err_flag = 1; + end + + if (!(INIT_SYNC_FF==0) && !(INIT_SYNC_FF==1)) begin + $error("[%s %0d-%0d] INIT_SYNC_FF (%0d) is outside of valid range. %m", "XPM_CDC", 2, 7, INIT_SYNC_FF); + drc_err_flag = 1; + end + + if (!(REG_OUTPUT==0) && !(REG_OUTPUT==1)) begin + $error("[%s %0d-%0d] REG_OUTPUT (%0d) is outside of valid range. %m", "XPM_CDC", 2, 6, REG_OUTPUT); + drc_err_flag = 1; + end + + if (!(SIM_ASSERT_CHK == 0) && !(SIM_ASSERT_CHK == 1)) begin + $error("[%s %0d-%0d] SIM_ASSERT_CHK (%0d) is outside of valid range. %m", "XPM_CDC", 2, 4, SIM_ASSERT_CHK); + drc_err_flag = 1; + end + + if (SIM_LOSSLESS_GRAY_CHK>1) begin + $error("[%s %0d-%0d] SIM_LOSSLESS_GRAY_CHK (%0d) is outside of valid range. %m", "XPM_CDC", 2, 5, SIM_LOSSLESS_GRAY_CHK); + drc_err_flag = 1; + end + + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of valid range. %m", "XPM_CDC", 2, 1, VERSION); + drc_err_flag = 1; + end + + if ((WIDTH < 2) || (WIDTH > 32)) begin + $error("[%s %0d-%0d] WIDTH (%0d) is outside of valid range of 2-32. %m", "XPM_CDC", 2, 3, WIDTH); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + end : config_drc_gray + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation only variable and signal assignment + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + `ifndef ONESPIN + `define XPM_CDC_BHVSIM_ONLY + tri0 glblGSR_xpmcdc = glbl.GSR; + `endif + // synthesis translate_on + + // Set Asynchronous Register property on synchronizers + (* XPM_CDC = "GRAY", ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] dest_graysync_ff [DEST_SYNC_FF-1:0]; + + `ifdef XPM_CDC_BHVSIM_ONLY + if (INIT_SYNC_FF == 1) begin + always @(glblGSR_xpmcdc) + if (glblGSR_xpmcdc) + force dest_graysync_ff = '{default:(0)}; + else + release dest_graysync_ff; + end + `endif + + wire [WIDTH-1:0] gray_enc; + reg [WIDTH-1:0] binval; + + reg [WIDTH-1:0] src_gray_ff; + wire [WIDTH-1:0] synco_gray; + wire [WIDTH-1:0] async_path; + reg [WIDTH-1:0] dest_out_bin_ff; + + always @(posedge dest_clk) begin + dest_graysync_ff[0] <= async_path; + + for (int syncstage = 1; syncstage < DEST_SYNC_FF ;syncstage = syncstage + 1) + dest_graysync_ff[syncstage] <= dest_graysync_ff [syncstage-1]; + end + + assign async_path = src_gray_ff; + + assign synco_gray = dest_graysync_ff[DEST_SYNC_FF-1]; + assign gray_enc = src_in_bin ^ {1'b0, src_in_bin[WIDTH-1:1]}; + + // Convert gray code back to binary + always_comb begin + binval[WIDTH-1] = synco_gray[WIDTH-1]; + for (int j = WIDTH - 2; j >= 0; j = j - 1) + binval[j] = binval[j+1] ^ synco_gray[j]; + end + + generate + if(REG_OUTPUT) begin : reg_out + assign dest_out_bin = dest_out_bin_ff; + end : reg_out + else begin : comb_out + assign dest_out_bin = binval; + end : comb_out + endgenerate + + // Instantiate Xilinx Synchronous Register + `ifdef XPM_CDC_BHVSIM_ONLY + if(INIT_SYNC_FF) begin + `XPM_XSRREG_INIT(src_clk, 1'b0, src_gray_ff, gray_enc, {WIDTH{1'b0}}, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(dest_clk, 1'b0, dest_out_bin_ff, binval, {WIDTH{1'b0}}, glblGSR_xpmcdc, 1'b0) + end else begin + `XPM_XSRREG(src_clk, 1'b0, src_gray_ff, gray_enc, {WIDTH{1'b0}}) + `XPM_XSRREG(dest_clk, 1'b0, dest_out_bin_ff, binval, {WIDTH{1'b0}}) + end + `else + `XPM_XSRREG(src_clk, 1'b0, src_gray_ff, gray_enc, {WIDTH{1'b0}}) + `XPM_XSRREG(dest_clk, 1'b0, dest_out_bin_ff, binval, {WIDTH{1'b0}}) + `endif + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation constructs + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + + initial begin : sim_check + #1; + if (SIM_ASSERT_CHK == 1) begin : sim_xil_check + `ifdef OBSOLETE + $warning("Vivado Simulator does not currently support the SystemVerilog Assertion syntax used within XPM_CDC. \ +Messages related to potential misuse will not be reported."); + `endif + end : sim_xil_check + end : sim_check + + `ifndef OBSOLETE + localparam logic [WIDTH-1:0] VALONE = {WIDTH{1'b0}}+1; + //To guarantee data is transfered into destination clock domain (asynchronous to source clock domain), input data + //must be sampled at the minimum by 2 destination clock edges. + if (SIM_ASSERT_CHK == 1) begin : min_sampling + assume property (@(posedge dest_clk) + !$stable(src_in_bin) |-> ##1 $stable(src_in_bin) [*2]) + else + $error("[%s %s-%0d] Input data at %0t is not stable long enough to be sampled twice by the destination clock. \ +Data in source domain may not transfer to destination clock domain.", "XPM_CDC_GRAY", "S", 1, $time); + end : min_sampling + + //Check that input only increments or decrements by one each time to avoid any loss of counter value being synchronized. + if ((SIM_ASSERT_CHK == 1)||(SIM_LOSSLESS_GRAY_CHK == 1)) begin : chk_input_incdec + assume property (@(posedge src_clk) + (!$stable(src_in_bin) && !$isunknown($past(src_in_bin))) |-> + ( (src_in_bin == ($past(src_in_bin)+VALONE) ) || (src_in_bin == ($past(src_in_bin)-VALONE)) ) ) + else + $error("[%s %s-%0d] Input data may be lost and may not be correctly synchronized. src_in_bin at %0t is not \ +incrementing or decrementing by one. This violates the usage guidance for this module. Please refer to the XPM_CDC \ +documentation in the libraries guide. \ +NOTE: If this assertion occurred after a system reset, then it can be safely ignored.", "XPM_CDC_GRAY", "S", 2, $time); + end : chk_input_incdec + `endif + + // synthesis translate_on + +endmodule : xpm_cdc_gray + + +// ------------------------------------------------------------------------------------------------------------------- +// Handshaking Clock Domain Crossing +// ------------------------------------------------------------------------------------------------------------------- +(* XPM_MODULE = "TRUE", XPM_CDC = "HANDSHAKE", KEEP_HIERARCHY = "TRUE" *) +module xpm_cdc_handshake #( + // Module parameters + parameter integer DEST_EXT_HSK = 1, + parameter integer DEST_SYNC_FF = 4, + parameter integer INIT_SYNC_FF = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer SRC_SYNC_FF = 4, + parameter integer VERSION = 0, + parameter integer WIDTH = 1 +) ( + // Module ports + input wire src_clk, + input wire [WIDTH-1:0] src_in, + input wire src_send, + output wire src_rcv, + + input wire dest_clk, + output wire [WIDTH-1:0] dest_out, + output wire dest_req, + input wire dest_ack +); + + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ------------------------------------------------------------------------------------------------------------------- + initial begin : config_drc_hsk + reg drc_err_flag; + drc_err_flag = 0; + + if (!(DEST_EXT_HSK==0) && !(DEST_EXT_HSK==1)) begin + $error("[%s %0d-%0d] DEST_EXT_HSK (%0d) is outside of valid range. %m", "XPM_CDC", 3, 5, DEST_EXT_HSK); + drc_err_flag = 1; + end + + if ((DEST_SYNC_FF < 2) || (DEST_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] DEST_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 3, 2, DEST_SYNC_FF); + drc_err_flag = 1; + end + + if (!(INIT_SYNC_FF==0) && !(INIT_SYNC_FF==1)) begin + $error("[%s %0d-%0d] INIT_SYNC_FF (%0d) is outside of valid range. %m", "XPM_CDC", 3, 7, INIT_SYNC_FF); + drc_err_flag = 1; + end + + if (!(SIM_ASSERT_CHK==0) && !(SIM_ASSERT_CHK==1)) begin + $error("[%s %0d-%0d] SIM_ASSERT_CHK (%0d) is outside of valid range. %m", "XPM_CDC", 3, 6, SIM_ASSERT_CHK); + drc_err_flag = 1; + end + + if ((SRC_SYNC_FF < 2) || (SRC_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] SRC_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 3, 3, SRC_SYNC_FF); + drc_err_flag = 1; + end + + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of valid range. %m", "XPM_CDC", 3, 1, VERSION); + drc_err_flag = 1; + end + + if ((WIDTH < 1) || (WIDTH > 1024)) begin + $error("[%s %0d-%0d] WIDTH (%0d) is outside of valid range of 1-1024. %m", "XPM_CDC", 3, 4, WIDTH); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + end : config_drc_hsk + + // ------------------------------------------------------------------------------------------------------------------- + // Local parameter definitions + // ------------------------------------------------------------------------------------------------------------------- + + // Set Asynchronous Register property on synchronizers + (* XPM_CDC = "HANDSHAKE" *) reg [WIDTH-1:0] dest_hsdata_ff; + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation only variable and signal assignment + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + `ifndef ONESPIN + `define XPM_CDC_BHVSIM_ONLY + tri0 glblGSR_xpmcdc = glbl.GSR; + `endif + // synthesis translate_on + + // We can do set max delay between source and dest. + // For option with no input register, we have to create a smart constraint + // for set max delay. + reg [WIDTH-1:0] src_hsdata_ff; + wire dest_req_nxt; + reg dest_req_ff; + (* DIRECT_ENABLE = "yes" *) wire dest_hsdata_en; + wire dest_req_ext_nxt; + reg dest_req_ext_ff; + wire [WIDTH-1:0] src_hsdata_nxt; + wire [WIDTH-1:0] dest_hsdata_nxt; + wire [WIDTH-1:0] src_data_src; + wire dest_req_sync; + wire dest_ack_sync_in; + reg src_sendd_ff; + wire src_sendd_nxt; + + // ------------------------------------------------------------------------------------------------------------------- + // xpm_cdc_single instantiation + // ------------------------------------------------------------------------------------------------------------------- + xpm_cdc_single # ( + .DEST_SYNC_FF (DEST_SYNC_FF ), + .INIT_SYNC_FF (INIT_SYNC_FF ), + .SRC_INPUT_REG (0 ), + .VERSION (VERSION ) + ) xpm_cdc_single_src2dest_inst ( + + .src_clk (src_clk ), + .dest_clk (dest_clk ), + .src_in (src_sendd_ff ), + .dest_out (dest_req_sync ) + ); + + //src_data is always registered once + assign src_data_src = src_hsdata_ff; + + assign src_hsdata_nxt = (src_sendd_ff == 1'b0) ? src_in : src_hsdata_ff; + assign dest_hsdata_nxt = src_data_src; + assign dest_out = dest_hsdata_ff; + assign dest_req_nxt = dest_req_sync; + assign dest_hsdata_en = ~dest_req_ff && dest_req_sync; + assign src_sendd_nxt = src_send; + + // ------------------------------------------------------------------------------------------------------------------- + // xpm_cdc_single instantiation + // ------------------------------------------------------------------------------------------------------------------- + xpm_cdc_single # ( + .DEST_SYNC_FF (SRC_SYNC_FF ), + .INIT_SYNC_FF (INIT_SYNC_FF ), + .SRC_INPUT_REG (0 ), + .VERSION (VERSION ) + ) xpm_cdc_single_dest2src_inst ( + .src_clk (dest_clk ), + .dest_clk (src_clk ), + .src_in (dest_ack_sync_in), + .dest_out (src_rcv ) + ); + + generate + if(DEST_EXT_HSK) begin : ext_desthsk + assign dest_ack_sync_in = dest_ack; + assign dest_req_ext_nxt = dest_req_sync ; + end : ext_desthsk + else begin : internal_desthsk + assign dest_ack_sync_in = dest_req_ff; + assign dest_req_ext_nxt = dest_req_sync & ~dest_req_ff; + end : internal_desthsk + endgenerate + + assign dest_req = dest_req_ext_ff; + + // Instantiate Xilinx Synchronous Register + `ifdef XPM_CDC_BHVSIM_ONLY + if(INIT_SYNC_FF) begin + `XPM_XSRREG_INIT(src_clk, 1'b0, src_sendd_ff, src_sendd_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(src_clk, 1'b0, src_hsdata_ff, src_hsdata_nxt, {WIDTH{1'b0}}, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREGEN_INIT(dest_clk, 1'b0, dest_hsdata_ff, dest_hsdata_nxt, dest_hsdata_en ,{WIDTH{1'b0}}, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(dest_clk, 1'b0, dest_req_ff, dest_req_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(dest_clk, 1'b0, dest_req_ext_ff, dest_req_ext_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + end else begin + `XPM_XSRREG(src_clk, 1'b0, src_sendd_ff, src_sendd_nxt, 1'b0) + `XPM_XSRREG(src_clk, 1'b0, src_hsdata_ff, src_hsdata_nxt, {WIDTH{1'b0}}) + `XPM_XSRREGEN(dest_clk, 1'b0, dest_hsdata_ff, dest_hsdata_nxt, dest_hsdata_en ,{WIDTH{1'b0}}) + `XPM_XSRREG(dest_clk, 1'b0, dest_req_ff, dest_req_nxt, 1'b0) + `XPM_XSRREG(dest_clk, 1'b0, dest_req_ext_ff, dest_req_ext_nxt, 1'b0) + end + `else + `XPM_XSRREG(src_clk, 1'b0, src_sendd_ff, src_sendd_nxt, 1'b0) + `XPM_XSRREG(src_clk, 1'b0, src_hsdata_ff, src_hsdata_nxt, {WIDTH{1'b0}}) + `XPM_XSRREGEN(dest_clk, 1'b0, dest_hsdata_ff, dest_hsdata_nxt, dest_hsdata_en ,{WIDTH{1'b0}}) + `XPM_XSRREG(dest_clk, 1'b0, dest_req_ff, dest_req_nxt, 1'b0) + `XPM_XSRREG(dest_clk, 1'b0, dest_req_ext_ff, dest_req_ext_nxt, 1'b0) + `endif + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation constructs + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + + initial begin : sim_check + #1; + if (SIM_ASSERT_CHK == 1) begin : sim_xil_check + `ifdef OBSOLETE + $warning("Vivado Simulator does not currently support the SystemVerilog Assertion syntax used within XPM_CDC. \ +Messages related to potential misuse will not be reported."); + `endif + end : sim_xil_check + end : sim_check + + `ifndef OBSOLETE + if (SIM_ASSERT_CHK == 1) begin : hsk_usage + //Checks for valid conditions in which the src_send signal can toggle (based on src_rcv value) + //Start new handshake after previous handshake completes. + assume property (@(posedge src_clk ) + (($past(src_send) == 0) && (src_send==1)) |-> !src_rcv ) + else + $error("[%s %s-%0d] New handshake (src_send transitioning to 1) at %0t shouldn't occur until the previous data \ +handshake completes (src_rcv must be 0). This violates the usage guidance for this module. Please refer to the \ +XPM_CDC documentation in the libraries guide.", "XPM_CDC_HANDSHAKE", "S", 1, $time); + + //Initiate completion of data transfer after receiving confirmation that destination has received data. + assume property (@(posedge src_clk ) + (($past(src_send) == 1) && (src_send==0)) |-> src_rcv ) + else + $error("[%s %s-%0d] Source cannot complete acknowledgement that destination has received the data at %0t until \ +source receives acknowledgement from destination. This violates the usage guidance for this module. Please refer \ +to the XPM_CDC documentation in the libraries guide.", "XPM_CDC_HANDSHAKE", "S", 2, $time); + + if (DEST_EXT_HSK == 1) begin :ext_dest_hsk + //Checks for valid conditions in which the dest_ack signal can toggle (based on dest_req value) + //Acknowledgement of data transfer should only occur after receiving a new data. + assume property (@(posedge dest_clk ) + (($past(dest_ack) == 0) && (dest_ack==1)) |-> dest_req ) + else + $error("[%s %s-%0d] Acknowledgement of a new handshake (dest_ack transitioning to 1) at %0t should occur \ +only when a new data transfer is received (dest_req must be 1). This violates the usage guidance for this module. \ +Please refer to the XPM_CDC documentation in the libraries guide.", "XPM_CDC_HANDSHAKE", "S", 3, $time); + + //Complete handshake of data transfer after receiving confirmation that source has received acknowledgement. + assume property (@(posedge dest_clk ) + (($past(dest_ack) == 1) && (dest_ack==0)) |-> !dest_req ) + else + $error("[%s %s-%0d] Destination cannot complete handshake at %0t until destination receives acknowledgement \ +from source. This violates the usage guidance for this module. Please refer to the XPM_CDC documentation in the \ +libraries guide.", "XPM_CDC_HANDSHAKE", "S", 4, $time); + end : ext_dest_hsk + + end : hsk_usage + `endif + + // synthesis translate_on + +endmodule : xpm_cdc_handshake + +// ------------------------------------------------------------------------------------------------------------------- +// Pulse Transfer +// ------------------------------------------------------------------------------------------------------------------- +// This is a module that takes a pulse from the source domain and converts it +// to a level to cross into the other domain, and then converting it back to a pulse +// in destination domain. +(* XPM_MODULE = "TRUE", XPM_CDC = "PULSE", KEEP_HIERARCHY = "TRUE" *) +module xpm_cdc_pulse #( + parameter integer DEST_SYNC_FF = 4, + parameter integer INIT_SYNC_FF = 0, + parameter integer REG_OUTPUT = 0, + parameter integer RST_USED = 1, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer VERSION = 0 +) ( + input wire src_clk, + input wire src_pulse, + input wire dest_clk, + input wire src_rst, + input wire dest_rst, + output wire dest_pulse +); + + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ------------------------------------------------------------------------------------------------------------------- + initial begin : config_drc_pulse + reg drc_err_flag; + drc_err_flag = 0; + + if ((DEST_SYNC_FF < 2) || (DEST_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] DEST_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 4, 2, DEST_SYNC_FF); + drc_err_flag = 1; + end + + if (!(INIT_SYNC_FF==0) && !(INIT_SYNC_FF==1)) begin + $error("[%s %0d-%0d] INIT_SYNC_FF (%0d) is outside of valid range. %m", "XPM_CDC", 4, 6, INIT_SYNC_FF); + drc_err_flag = 1; + end + + if (!(REG_OUTPUT == 0) && !(REG_OUTPUT == 1)) begin + $error("[%s %0d-%0d] REG_OUTPUT (%0d) value is outside of valid range. %m", "XPM_CDC", 4, 5, REG_OUTPUT); + drc_err_flag = 1; + end + + if (!(RST_USED == 0) && !(RST_USED == 1)) begin + $error("[%s %0d-%0d] RST_USED (%0d) value is outside of valid range. %m", "XPM_CDC", 4, 3, RST_USED); + drc_err_flag = 1; + end + + if (!(SIM_ASSERT_CHK==0) && !(SIM_ASSERT_CHK==1)) begin + $error("[%s %0d-%0d] SIM_ASSERT_CHK (%0d) is outside of valid range. %m", "XPM_CDC", 4, 4, SIM_ASSERT_CHK); + drc_err_flag = 1; + end + + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of valid range. %m", "XPM_CDC", 4, 1, VERSION); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + end : config_drc_pulse + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation only variable and signal assignment + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + `ifndef ONESPIN + `define XPM_CDC_BHVSIM_ONLY + tri0 glblGSR_xpmcdc = glbl.GSR; + `endif + // synthesis translate_on + + // If toggle flop is not initialized,then it can be un-known forever. + // It is assumed that there is no loss of coverage either way. + // For edge detect, we would want the logic to be more controlled. + reg src_level_ff = 1'b0; + + reg src_in_ff; + wire src_level_nxt; + wire src_edge_det; + wire src_sync_in; + + wire dest_sync_out; + wire dest_event_nxt; + reg dest_event_ff; + wire dest_sync_qual; + + wire src_rst_qual; + wire dest_rst_qual; + + wire dest_pulse_int; + reg dest_pulse_ff; + + //Assignments + assign src_edge_det = src_pulse & ~src_in_ff; + assign src_level_nxt = src_level_ff ^ src_edge_det; + assign src_sync_in = src_level_ff; + assign dest_event_nxt = dest_sync_qual; + assign dest_pulse_int = dest_sync_qual ^ dest_event_ff; + assign dest_sync_qual = dest_sync_out & ~dest_rst_qual; + + generate + if(RST_USED) begin : use_rst + assign src_rst_qual = src_rst; + assign dest_rst_qual = dest_rst; + end : use_rst + else begin : no_rst + assign src_rst_qual = 1'b0; + assign dest_rst_qual = 1'b0; + end : no_rst + endgenerate + + generate + if(REG_OUTPUT) begin : reg_out + assign dest_pulse = dest_pulse_ff; + end : reg_out + else begin : comb_out + assign dest_pulse = dest_pulse_int; + end : comb_out + endgenerate + + xpm_cdc_single # ( + .DEST_SYNC_FF (DEST_SYNC_FF ), + .INIT_SYNC_FF (INIT_SYNC_FF ), + .SRC_INPUT_REG (0 ), + .VERSION (VERSION ) + ) xpm_cdc_single_inst ( + .src_clk (src_clk ), + .dest_clk (dest_clk ), + .src_in (src_sync_in ), + .dest_out (dest_sync_out ) + ); + + // Instantiate Xilinx Synchronous Register + `ifdef XPM_CDC_BHVSIM_ONLY + if(INIT_SYNC_FF) begin + `XPM_XSRREG_INIT(src_clk, src_rst_qual, src_in_ff, src_pulse, 1'b0, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(src_clk, src_rst_qual, src_level_ff, src_level_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(dest_clk, dest_rst_qual, dest_event_ff, dest_event_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(dest_clk, dest_rst_qual, dest_pulse_ff, dest_pulse_int, 1'b0, glblGSR_xpmcdc, 1'b0) + end else begin + `XPM_XSRREG(src_clk, src_rst_qual, src_in_ff, src_pulse, 1'b0) + `XPM_XSRREG(src_clk, src_rst_qual, src_level_ff, src_level_nxt, 1'b0) + `XPM_XSRREG(dest_clk, dest_rst_qual, dest_event_ff, dest_event_nxt, 1'b0) + `XPM_XSRREG(dest_clk, dest_rst_qual, dest_pulse_ff, dest_pulse_int, 1'b0) + end + `else + `XPM_XSRREG(src_clk, src_rst_qual, src_in_ff, src_pulse, 1'b0) + `XPM_XSRREG(src_clk, src_rst_qual, src_level_ff, src_level_nxt, 1'b0) + `XPM_XSRREG(dest_clk, dest_rst_qual, dest_event_ff, dest_event_nxt, 1'b0) + `XPM_XSRREG(dest_clk, dest_rst_qual, dest_pulse_ff, dest_pulse_int, 1'b0) + `endif + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation constructs + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + + initial begin : sim_check + #1; + if (SIM_ASSERT_CHK == 1) begin : sim_xil_check + `ifdef OBSOLETE + $warning("Vivado Simulator does not currently support the SystemVerilog Assertion syntax used within XPM_CDC. \ +Messages related to potential misuse will not be reported."); + `endif + end : sim_xil_check + end : sim_check + + `ifndef OBSOLETE + if (SIM_ASSERT_CHK == 1 && RST_USED == 1) begin : chk_rst + //Verify that src_pulse doesn't change during source or dest reset + assume property ( @(posedge src_clk) + (($past(src_pulse) == 0) && (src_pulse==1)) |-> !src_rst ) + else + $warning("[%s %s-%0d] Input should not change when src_rst is asserted. Pulse transfer initiated at time %0t \ +may fail.", "XPM_CDC_PULSE", "S", 1, $time); + + assume property ( @(posedge dest_clk) + (($past(src_pulse) == 0) && (src_pulse==1)) |-> !dest_rst ) + else + $warning("[%s %s-%0d] Input should not change when dest_rst is asserted. Pulse transfer initiated at time %0t \ +may fail.", "XPM_CDC_PULSE", "S", 1, $time); + end : chk_rst + `endif + + // synthesis translate_on + +endmodule : xpm_cdc_pulse + +// ------------------------------------------------------------------------------------------------------------------- +// Single-bit Array Synchronizer +// ------------------------------------------------------------------------------------------------------------------- +(* XPM_MODULE = "TRUE", XPM_CDC = "ARRAY_SINGLE", KEEP_HIERARCHY = "TRUE" *) +module xpm_cdc_array_single # ( + parameter integer DEST_SYNC_FF = 4, + parameter integer INIT_SYNC_FF = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer SRC_INPUT_REG = 1, + parameter integer VERSION = 0, + parameter integer WIDTH = 2 +) ( + input wire src_clk, + input wire [WIDTH-1:0] src_in, + input wire dest_clk, + output wire [WIDTH-1:0] dest_out +); + + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ------------------------------------------------------------------------------------------------------------------- + initial begin : config_drc_array_single + reg drc_err_flag; + drc_err_flag = 0; + + if ((DEST_SYNC_FF < 2) || (DEST_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] DEST_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 5, 2, DEST_SYNC_FF); + drc_err_flag = 1; + end + + if (!(INIT_SYNC_FF==0) && !(INIT_SYNC_FF==1)) begin + $error("[%s %0d-%0d] INIT_SYNC_FF (%0d) is outside of valid range. %m", "XPM_CDC", 5, 6, INIT_SYNC_FF); + drc_err_flag = 1; + end + + if (!(SIM_ASSERT_CHK==0) && !(SIM_ASSERT_CHK==1)) begin + $error("[%s %0d-%0d] SIM_ASSERT_CHK (%0d) is outside of valid range. %m", "XPM_CDC", 5, 5, SIM_ASSERT_CHK); + drc_err_flag = 1; + end + + if (!(SRC_INPUT_REG == 0) && !(SRC_INPUT_REG == 1)) begin + $error("[%s %0d-%0d] SRC_INPUT_REG (%0d) value is outside of valid range. %m", "XPM_CDC", 5, 3, SRC_INPUT_REG); + drc_err_flag = 1; + end + + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of valid range. %m", "XPM_CDC", 5, 1, VERSION); + drc_err_flag = 1; + end + + if ((WIDTH < 1) || (WIDTH > 1024)) begin + $error("[%s %0d-%0d] WIDTH (%0d) is outside of valid range of 1-1024. %m", "XPM_CDC", 5, 4, WIDTH); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + end : config_drc_array_single + +(* XPM_CDC = "ARRAY_SINGLE", ASYNC_REG = "TRUE" *) reg [WIDTH-1:0] syncstages_ff [DEST_SYNC_FF-1:0]; + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation only variable and signal assignment + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + `ifndef ONESPIN + `define XPM_CDC_BHVSIM_ONLY + tri0 glblGSR_xpmcdc = glbl.GSR; + `endif + // synthesis translate_on + + reg [WIDTH-1:0] src_ff; + wire [WIDTH-1:0] src_inqual; + wire [WIDTH-1:0] async_path_bit; + + assign dest_out = syncstages_ff[DEST_SYNC_FF-1]; + + `ifdef XPM_CDC_BHVSIM_ONLY + if (INIT_SYNC_FF == 1) begin + always @(glblGSR_xpmcdc) + if (glblGSR_xpmcdc) + force syncstages_ff = '{default:(0)}; + else + release syncstages_ff; + end + `endif + + always @(posedge dest_clk) begin + syncstages_ff[0] <= async_path_bit; + + for (int syncstage = 1; syncstage < DEST_SYNC_FF ;syncstage = syncstage + 1) + syncstages_ff[syncstage] <= syncstages_ff [syncstage-1]; + end + + assign async_path_bit = src_inqual; + + // Virtual mux: Register at input optional. + generate + if (SRC_INPUT_REG) begin : extra_inreg + assign src_inqual = src_ff; + end : extra_inreg + else begin : no_extra_inreg + assign src_inqual = src_in; + end : no_extra_inreg + endgenerate + + genvar vara_i; + generate + // Instantiate Xilinx Synchronous Register + `ifdef XPM_CDC_BHVSIM_ONLY + if(INIT_SYNC_FF) begin + `XPM_XSRREG_INIT(src_clk, 1'b0, src_ff, src_in, {WIDTH{1'b0}}, glblGSR_xpmcdc, 1'b0) + end else begin + `XPM_XSRREG(src_clk, 1'b0, src_ff, src_in,{WIDTH{1'b0}}) + end + `else + `XPM_XSRREG(src_clk, 1'b0, src_ff, src_in, {WIDTH{1'b0}}) + `endif + endgenerate + + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation constructs + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + + initial begin : sim_check + #1; + if (SIM_ASSERT_CHK == 1) begin : sim_xil_check + `ifdef OBSOLETE + $warning("Vivado Simulator does not currently support the SystemVerilog Assertion syntax used within XPM_CDC. \ +Messages related to potential misuse will not be reported."); + `endif + end : sim_xil_check + end : sim_check + + `ifndef OBSOLETE + //S_A2: To guarantee data is transfered into destination clock domain (asynchronous to source clock domain), input data + //must be sampled at the minimum by 2 destination clock edges. + generate + if (SIM_ASSERT_CHK == 1) begin : min_sampling + for (genvar i = 0; i < WIDTH; i++) begin : chk_bits + assume property (@(posedge dest_clk) + !( $stable(src_in[i]) ) |-> ##1 $stable(src_in[i]) [*2]) + else + $error("[%s %s-%0d] Input data (src_in[%0d]) at %0t is not stable long enough to be sampled twice by the destination clock. \ +Data in source domain may not transfer to destination clock domain.", "XPM_CDC_ARRAY_SINGLE", "S", 1, i, $time); + end : chk_bits + end : min_sampling + endgenerate + `endif + + // synthesis translate_on + +endmodule : xpm_cdc_array_single + +// ------------------------------------------------------------------------------------------------------------------- +// Synchronous Reset Synchronizer +// ------------------------------------------------------------------------------------------------------------------- +(* XPM_MODULE = "TRUE", XPM_CDC = "SYNC_RST", KEEP_HIERARCHY = "TRUE" *) +module xpm_cdc_sync_rst # ( + parameter integer DEST_SYNC_FF = 4, + parameter integer INIT = 1, + parameter integer INIT_SYNC_FF = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer VERSION = 0 + ) ( + input wire src_rst, + input wire dest_clk, + output wire dest_rst +); + + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ------------------------------------------------------------------------------------------------------------------- + initial begin : config_drc + reg drc_err_flag; + drc_err_flag = 0; + + if ((DEST_SYNC_FF < 2) || (DEST_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] DEST_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 6, 2, DEST_SYNC_FF); + drc_err_flag = 1; + end + + if (!(INIT == 0) && !(INIT == 1)) begin + $error("[%s %0d-%0d] INIT (%0d) value is outside of valid range. %m", "XPM_CDC", 6, 3, INIT); + drc_err_flag = 1; + end + + if (!(INIT_SYNC_FF==0) && !(INIT_SYNC_FF==1)) begin + $error("[%s %0d-%0d] INIT_SYNC_FF (%0d) is outside of valid range. %m", "XPM_CDC", 6, 5, INIT_SYNC_FF); + drc_err_flag = 1; + end + + if (!(SIM_ASSERT_CHK==0) && !(SIM_ASSERT_CHK==1)) begin + $error("[%s %0d-%0d] SIM_ASSERT_CHK (%0d) is outside of valid range. %m", "XPM_CDC", 6, 4, SIM_ASSERT_CHK); + drc_err_flag = 1; + end + + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of valid range. %m", "XPM_CDC", 6, 1, VERSION); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + end : config_drc + + // Define local parameter for settings + localparam DEF_VAL = (INIT == 1) ? 1'b1 : 1'b0; + + // Set asynchronous register property on synchronizers and initialize register with INIT value + (* XPM_CDC = "SYNC_RST", ASYNC_REG = "TRUE" *) reg [DEST_SYNC_FF-1:0] syncstages_ff = {DEST_SYNC_FF{DEF_VAL}}; + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation only variable and signal assignment + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + `ifndef ONESPIN + `define XPM_CDC_BHVSIM_ONLY + tri0 glblGSR_xpmcdc = glbl.GSR; + `endif + // synthesis translate_on + + wire async_path_bit; + + assign dest_rst = syncstages_ff[DEST_SYNC_FF-1]; + assign async_path_bit = src_rst; + + // Instantiate Xilinx Synchronous Register + `ifdef XPM_CDC_BHVSIM_ONLY + if(INIT_SYNC_FF) begin + `XPM_XSRREG_INIT(dest_clk, 1'b0, syncstages_ff, { syncstages_ff[DEST_SYNC_FF-2:0], async_path_bit}, {DEST_SYNC_FF{1'b0}}, glblGSR_xpmcdc, {DEST_SYNC_FF{DEF_VAL}}) + end else begin + `XPM_XSRREG(dest_clk, 1'b0, syncstages_ff, { syncstages_ff[DEST_SYNC_FF-2:0], async_path_bit}, {DEST_SYNC_FF{1'b0}}) + end + `else + `XPM_XSRREG(dest_clk, 1'b0, syncstages_ff, { syncstages_ff[DEST_SYNC_FF-2:0], async_path_bit}, {DEST_SYNC_FF{1'b0}}) + `endif + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation constructs + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + + initial begin : sim_check + #1; + if (SIM_ASSERT_CHK == 1) begin : sim_xil_check + `ifdef OBSOLETE + $warning("Vivado Simulator does not currently support the SystemVerilog Assertion syntax used within XPM_CDC. \ +Messages related to potential misuse will not be reported."); + `endif + end : sim_xil_check + end : sim_check + + `ifndef OBSOLETE + //To guarantee data is transfered into destination clock domain (asynchronous to source clock domain), input data + //must be sampled at the minimum by 2 destination clock edges. + if (SIM_ASSERT_CHK == 1) begin : min_sampling + assume property (@(posedge dest_clk) + ! $stable(src_rst) |-> ##1 $stable(src_rst) [*2]) + else + $error ("[%s %s-%0d] Input data at %0t is not stable long enough to be sampled twice by the destination clock. \ +Reset from source domain may not transfer to destination clock domain.", "XPM_CDC_SYNC_RST", "S", 1, $time); + end : min_sampling + + `endif + + // synthesis translate_on + +endmodule : xpm_cdc_sync_rst + +// ------------------------------------------------------------------------------------------------------------------- +// Asynchronous Reset Synchronizer +// ------------------------------------------------------------------------------------------------------------------- +(* XPM_MODULE = "TRUE", XPM_CDC = "ASYNC_RST", KEEP_HIERARCHY = "TRUE" *) +module xpm_cdc_async_rst # ( + parameter integer DEST_SYNC_FF = 4, + parameter integer INIT_SYNC_FF = 0, + parameter integer RST_ACTIVE_HIGH = 0, + parameter integer VERSION = 0 + ) ( + input wire src_arst, + input wire dest_clk, + output wire dest_arst +); + + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ------------------------------------------------------------------------------------------------------------------- + initial begin : config_drc_async_rst + reg drc_err_flag; + drc_err_flag = 0; + + if ((DEST_SYNC_FF < 2) || (DEST_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] DEST_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 7, 2, DEST_SYNC_FF); + drc_err_flag = 1; + end + + if (!(INIT_SYNC_FF==0) && !(INIT_SYNC_FF==1)) begin + $error("[%s %0d-%0d] INIT_SYNC_FF (%0d) is outside of valid range. %m", "XPM_CDC", 7, 4, INIT_SYNC_FF); + drc_err_flag = 1; + end + + if (!(RST_ACTIVE_HIGH == 0) && !(RST_ACTIVE_HIGH == 1)) begin + $error("[%s %0d-%0d] RST_ACTIVE_HIGH (%0d) value is outside of valid range. %m", "XPM_CDC", 7, 3, RST_ACTIVE_HIGH); + drc_err_flag = 1; + end + + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of valid range. %m", "XPM_CDC", 7, 1, VERSION); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + end : config_drc_async_rst + + // ------------------------------------------------------------------------------------------------------------------- + // Local parameter definitions + // ------------------------------------------------------------------------------------------------------------------- + + // Define local parameter for settings + localparam DEF_VAL = (RST_ACTIVE_HIGH == 1) ? 1'b0 : 1'b1; + localparam INV_DEF_VAL = (RST_ACTIVE_HIGH == 0) ? 1'b0 : 1'b1; + + // Set asynchronous register property on synchronizers and initialize register with default value + (* XPM_CDC = "ASYNC_RST", ASYNC_REG = "TRUE" *) reg [DEST_SYNC_FF-1:0] arststages_ff = {DEST_SYNC_FF{DEF_VAL}}; + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation only variable and signal assignment + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + `ifndef ONESPIN + `define XPM_CDC_BHVSIM_ONLY + tri0 glblGSR_xpmcdc = glbl.GSR; + `endif + // synthesis translate_on + + wire async_path_bit; + wire reset_pol; + wire reset_polo; + + assign reset_polo = arststages_ff[DEST_SYNC_FF-1]; + assign async_path_bit = (RST_ACTIVE_HIGH == 1) ? 1'b0 : 1'b1; + assign reset_pol = src_arst ^ ~RST_ACTIVE_HIGH; + assign dest_arst = reset_polo; + + // Instantiate Xilinx Asynchronous Clear Register + `ifdef XPM_CDC_BHVSIM_ONLY + if(INIT_SYNC_FF) begin + `XPM_XARREG_INIT(dest_clk, reset_pol, arststages_ff, { arststages_ff[DEST_SYNC_FF-2:0], async_path_bit}, {DEST_SYNC_FF{INV_DEF_VAL}}, glblGSR_xpmcdc, {DEST_SYNC_FF{DEF_VAL}}) + end else begin + `XPM_XARREG(dest_clk, reset_pol, arststages_ff, { arststages_ff[DEST_SYNC_FF-2:0], async_path_bit}, {DEST_SYNC_FF{INV_DEF_VAL}}) + end + `else + `XPM_XARREG(dest_clk, reset_pol, arststages_ff, { arststages_ff[DEST_SYNC_FF-2:0], async_path_bit}, {DEST_SYNC_FF{INV_DEF_VAL}}) + `endif + +endmodule : xpm_cdc_async_rst + + +// ------------------------------------------------------------------------------------------------------------------- +// Low Latency Handshaking Clock Domain Crossing +// ------------------------------------------------------------------------------------------------------------------- +(* XPM_MODULE = "TRUE", XPM_CDC = "LOW_LATENCY_HANDSHAKE", KEEP_HIERARCHY = "TRUE" *) +module xpm_cdc_low_latency_handshake #( + // Module parameters + parameter integer DEST_EXT_HSK = 1, + parameter integer DEST_SYNC_FF = 4, + parameter integer INIT_SYNC_FF = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer SRC_SYNC_FF = 4, + parameter integer VERSION = 0, + parameter integer WIDTH = 1 +) ( + // Module ports + input wire src_clk, + input wire [WIDTH-1:0] src_in, + input wire src_valid, + output wire src_ready, + + input wire dest_clk, + output wire [WIDTH-1:0] dest_out, + output wire dest_valid, + input wire dest_ready +); + + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ---------------- + initial begin : config_drc_hs + reg drc_err_flag; + drc_err_flag = 0; + + if (!(DEST_EXT_HSK==0) && !(DEST_EXT_HSK==1)) begin + $error("[%s %0d-%0d] DEST_EXT_HSK (%0d) is outside of valid range. %m", "XPM_CDC", 8, 5, DEST_EXT_HSK); + drc_err_flag = 1; + end + + if ((DEST_SYNC_FF < 2) || (DEST_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] DEST_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 8, 2, DEST_SYNC_FF); + drc_err_flag = 1; + end + + if (!(INIT_SYNC_FF==0) && !(INIT_SYNC_FF==1)) begin + $error("[%s %0d-%0d] INIT_SYNC_FF (%0d) is outside of valid range. %m", "XPM_CDC", 8, 7, INIT_SYNC_FF); + drc_err_flag = 1; + end + + if (!(SIM_ASSERT_CHK==0) && !(SIM_ASSERT_CHK==1)) begin + $error("[%s %0d-%0d] SIM_ASSERT_CHK (%0d) is outside of valid range. %m", "XPM_CDC", 8, 6, SIM_ASSERT_CHK); + drc_err_flag = 1; + end + + if ((SRC_SYNC_FF < 2) || (SRC_SYNC_FF > 10)) begin + $error("[%s %0d-%0d] SRC_SYNC_FF (%0d) is outside of valid range of 2-10. %m", "XPM_CDC", 8, 3, SRC_SYNC_FF); + drc_err_flag = 1; + end + + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of valid range. %m", "XPM_CDC", 8, 1, VERSION); + drc_err_flag = 1; + end + + if ((WIDTH < 1) || (WIDTH > 2048)) begin + $error("[%s %0d-%0d] WIDTH (%0d) is outside of valid range of 1-2048. %m", "XPM_CDC", 8, 4, WIDTH); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + + end : config_drc_hs + + // ------------------------------------------------------------------------------------------------------------------- + // Local parameter definitions + // ------------------------------------------------------------------------------------------------------------------- + + // Set Asynchronous Register property on synchronizers + (* XPM_CDC = "LOW_LATENCY_HANDSHAKE" *) reg [WIDTH-1:0] dest_hsdata_ff; + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation only variable and signal assignment + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + `ifndef ONESPIN + `define XPM_CDC_BHVSIM_ONLY + tri0 glblGSR_xpmcdc = glbl.GSR; + `endif + // synthesis translate_on + + reg [WIDTH-1:0] src_hsdata_ff; + wire src_valid_nxt; + wire src_count_nxt; + reg src_count_ff = 1'b0; + wire src_count_sync_ff; + (* DIRECT_ENABLE = "yes" *) wire dest_hsdata_ff_en; + reg dest_valid_ext_ff; + wire dest_valid_nxt; + wire dest_ready_in; + wire dest_ready_nxt; + wire dest_count_nxt; + wire dest_count_eq; + reg dest_count_ff = 1'b0; + wire dest_count_sync_ff; + wire src_count_eq; + wire src_ready_nxt; + reg src_ready_ext_ff; + + assign src_valid_nxt = src_valid && src_ready; + assign src_count_nxt = (src_valid_nxt == 1'b1) ? (src_count_ff+1'b1) : src_count_ff; + + assign dest_ready_nxt = dest_valid_ext_ff && dest_ready_in ; + assign dest_count_nxt = (dest_ready_nxt == 1'b1) ? (dest_count_ff+1'b1) : dest_count_ff; + + assign dest_count_eq = (src_count_sync_ff == dest_count_ff) ? 1'b1 : 1'b0; + assign dest_hsdata_ff_en = !dest_count_eq && !dest_valid_ext_ff; + assign dest_valid_nxt = !dest_count_eq && !dest_ready_nxt; + assign dest_valid = dest_valid_ext_ff; + + + assign src_count_eq = (src_count_ff == dest_count_sync_ff) ? 1'b1 : 1'b0; + assign src_ready_nxt = src_count_eq && !src_valid_nxt; + assign src_ready = src_ready_ext_ff; + + assign dest_out = dest_hsdata_ff; + + generate + if(DEST_EXT_HSK) begin : ext_desthsk + assign dest_ready_in = dest_ready; + end : ext_desthsk + else begin : internal_desthsk + assign dest_ready_in = 1'b1; + end : internal_desthsk + endgenerate + + //Instantiate Xilinx Synchronous Register + `ifdef XPM_CDC_BHVSIM_ONLY + if(INIT_SYNC_FF) begin + `XPM_XSRREGEN_INIT(src_clk, 1'b0, src_hsdata_ff, src_in, src_valid_nxt ,{WIDTH{1'b0}}, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREGEN_INIT(dest_clk, 1'b0, dest_hsdata_ff, src_hsdata_ff, dest_hsdata_ff_en, {WIDTH{1'b0}}, glblGSR_xpmcdc, 1'b0) + + `XPM_XSRREG_INIT(src_clk, 1'b0, src_count_ff, src_count_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(dest_clk, 1'b0, dest_count_ff, dest_count_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + + `XPM_XSRREG_INIT(dest_clk, 1'b0, dest_valid_ext_ff, dest_valid_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + `XPM_XSRREG_INIT(src_clk, 1'b0, src_ready_ext_ff, src_ready_nxt, 1'b0, glblGSR_xpmcdc, 1'b0) + + end + else begin // !if (INIT_SYNC_FF) + + `XPM_XSRREGEN(src_clk, 1'b0, src_hsdata_ff, src_in, src_valid_nxt ,{WIDTH{1'b0}}) + `XPM_XSRREGEN(dest_clk, 1'b0, dest_hsdata_ff, src_hsdata_ff, dest_hsdata_ff_en, {WIDTH{1'b0}}) + + `XPM_XSRREG(src_clk, 1'b0, src_count_ff, src_count_nxt, 1'b0) + `XPM_XSRREG(dest_clk, 1'b0, dest_count_ff, dest_count_nxt, 1'b0) + + `XPM_XSRREG(dest_clk, 1'b0, dest_valid_ext_ff, dest_valid_nxt, 1'b0) + `XPM_XSRREG(src_clk, 1'b0, src_ready_ext_ff, src_ready_nxt, 1'b0) + + end + `else // !`ifdef XPM_CDC_BHVSIM_ONLY + + `XPM_XSRREGEN(src_clk, 1'b0, src_hsdata_ff, src_in, src_valid_nxt ,{WIDTH{1'b0}}) + `XPM_XSRREGEN(dest_clk, 1'b0, dest_hsdata_ff, src_hsdata_ff, dest_hsdata_ff_en,{WIDTH{1'b0}}) + + `XPM_XSRREG(src_clk, 1'b0, src_count_ff, src_count_nxt, 1'b0) + `XPM_XSRREG(dest_clk, 1'b0, dest_count_ff, dest_count_nxt, 1'b0) + + `XPM_XSRREG(dest_clk, 1'b0, dest_valid_ext_ff, dest_valid_nxt, 1'b0) + `XPM_XSRREG(src_clk, 1'b0, src_ready_ext_ff, src_ready_nxt, 1'b0) + + `endif + + // ------------------------------------------------------------------------------------------------------------------- + // xpm_cdc_single instantiation + // ------------------------------------------------------------------------------------------------------------------- + xpm_cdc_single # ( + .DEST_SYNC_FF (DEST_SYNC_FF ), + .INIT_SYNC_FF (INIT_SYNC_FF ), + .SRC_INPUT_REG (0 ), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK), + .VERSION (VERSION ) + ) xpm_cdc_single_src2dest_inst ( + + .src_clk (src_clk ), + .dest_clk (dest_clk ), + .src_in (src_count_ff ), + .dest_out (src_count_sync_ff ) + ); + + // ------------------------------------------------------------------------------------------------------------------- + // xpm_cdc_single instantiation + // ------------------------------------------------------------------------------------------------------------------- + xpm_cdc_single # ( + .DEST_SYNC_FF (SRC_SYNC_FF ), + .INIT_SYNC_FF (INIT_SYNC_FF ), + .SRC_INPUT_REG (0 ), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK), + .VERSION (VERSION ) + ) xpm_cdc_single_dest2src_inst ( + .src_clk (dest_clk ), + .dest_clk (src_clk ), + .src_in (dest_count_ff ), + .dest_out (dest_count_sync_ff ) + ); + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation constructs + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + initial begin : sim_check + #1; + if (SIM_ASSERT_CHK == 1) begin : sim_xil_check + `ifdef OBSOLETE + $warning("Vivado Simulator does not currently support the SystemVerilog Assertion syntax used within XPM_CDC. \ +Messages related to potential misuse will not be reported."); + `endif + end : sim_xil_check + end : sim_check + // synthesis translate_on + + endmodule : xpm_cdc_low_latency_handshake + +`default_nettype wire + +`undef XPM_XSRREG +`undef XPM_XSRREGEN +`undef XPM_XARREG +`undef XPM_XSRREG_INIT +`undef XPM_XSRREGEN_INIT +`undef XPM_XARREG_INIT diff --git a/xpm/xpm_fifo.sv b/xpm/xpm_fifo.sv new file mode 100644 index 0000000..ecf552f --- /dev/null +++ b/xpm/xpm_fifo.sv @@ -0,0 +1,5082 @@ +//------------------------------------------------------------------------------ +// (c) Copyright 2016 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. +//------------------------------------------------------------------------------ + +// *************************** +// * DO NOT MODIFY THIS FILE * +// *************************** + +`timescale 1ps/1ps +`default_nettype none +(* XPM_MODULE = "TRUE", KEEP_HIERARCHY = "SOFT" *) +module xpm_fifo_base # ( + + // Common module parameters + parameter integer COMMON_CLOCK = 1, + parameter integer RELATED_CLOCKS = 0, + parameter integer FIFO_MEMORY_TYPE = 0, + parameter integer ECC_MODE = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer CASCADE_HEIGHT = 0, + + parameter integer FIFO_WRITE_DEPTH = 2048, + parameter integer WRITE_DATA_WIDTH = 32, + parameter integer WR_DATA_COUNT_WIDTH = 12, + parameter integer PROG_FULL_THRESH = 10, + parameter USE_ADV_FEATURES = "0707", + + parameter READ_MODE = 0, + parameter FIFO_READ_LATENCY = 1, + parameter integer READ_DATA_WIDTH = WRITE_DATA_WIDTH, + parameter integer RD_DATA_COUNT_WIDTH = 12, + parameter integer PROG_EMPTY_THRESH = 10, + parameter DOUT_RESET_VALUE = "", + parameter integer CDC_DEST_SYNC_FF = 2, + parameter integer FULL_RESET_VALUE = 0, + parameter integer REMOVE_WR_RD_PROT_LOGIC = 0, + + parameter integer WAKEUP_TIME = 0, + parameter integer VERSION = 1 + +) ( + + // Common module ports + input wire sleep, + input wire rst, + + // Write Domain ports + input wire wr_clk, + input wire wr_en, + input wire [WRITE_DATA_WIDTH-1:0] din, + output wire full, + output wire full_n, + output wire prog_full, + output wire [WR_DATA_COUNT_WIDTH-1:0] wr_data_count, + output wire overflow, + output wire wr_rst_busy, + output wire almost_full, + output wire wr_ack, + + // Read Domain ports + input wire rd_clk, + input wire rd_en, + output wire [READ_DATA_WIDTH-1:0] dout, + output wire empty, + output wire prog_empty, + output wire [RD_DATA_COUNT_WIDTH-1:0] rd_data_count, + output wire underflow, + output wire rd_rst_busy, + output wire almost_empty, + output wire data_valid, + + // ECC Related ports + input wire injectsbiterr, + input wire injectdbiterr, + output wire sbiterr, + output wire dbiterr +); + + function integer clog2; + input integer value; + begin + value = value-1; + for (clog2=0; value>0; clog2=clog2+1) + value = value>>1; + end + endfunction + // Function to convert ASCII value to binary + function [3:0] str2bin; + input [7:0] str_val_ascii; + if((str_val_ascii == 8'h30) || (str_val_ascii == 8'h31) || + (str_val_ascii == 8'h32) || (str_val_ascii == 8'h33) || + (str_val_ascii == 8'h34) || (str_val_ascii == 8'h35) || + (str_val_ascii == 8'h36) || (str_val_ascii == 8'h37) || + (str_val_ascii == 8'h38) || (str_val_ascii == 8'h39) || + (str_val_ascii == 8'h41) || (str_val_ascii == 8'h42) || + (str_val_ascii == 8'h43) || (str_val_ascii == 8'h44) || + (str_val_ascii == 8'h45) || (str_val_ascii == 8'h46) || + (str_val_ascii == 8'h61) || (str_val_ascii == 8'h62) || + (str_val_ascii == 8'h63) || (str_val_ascii == 8'h64) || + (str_val_ascii == 8'h65) || (str_val_ascii == 8'h66) || + (str_val_ascii == 8'h00)) begin + if (!str_val_ascii[6]) + str2bin = str_val_ascii[3:0]; + else begin + str2bin [3] = 1'b1; + str2bin [2] = str_val_ascii[2] | (str_val_ascii[1] & str_val_ascii[0]); + str2bin [1] = str_val_ascii[0] ^ str_val_ascii[1]; + str2bin [0] = !str_val_ascii[0]; + end + end + else + $error("Found Invalid character while parsing the string, please cross check the value specified for either READ_RESET_VALUE_A|B or MEMORY_INIT_PARAM (if initialization of memory through parameter is used). XPM_MEMORY supports strings (hex) that contains characters 0-9, A-F and a-f."); + endfunction + // Function that parses the complete reset value string + function logic [15:0] hstr2bin; + input [16*8-1 : 0] hstr_val; + integer rst_loop_a; + localparam integer rsta_loop_iter = 16; + logic [rsta_loop_iter-1 : 0] rst_val_conv_a_i; + for (rst_loop_a=1; rst_loop_a <= rsta_loop_iter/4; rst_loop_a = rst_loop_a+1) begin + rst_val_conv_a_i[(rst_loop_a*4)-1 -: 4] = str2bin(hstr_val[(rst_loop_a*8)-1 -: 8]); + end + return rst_val_conv_a_i[15:0]; + endfunction + + + localparam invalid = 0; + localparam stage1_valid = 2; + localparam stage2_valid = 1; + localparam both_stages_valid = 3; + + reg [1:0] curr_fwft_state = invalid; + reg [1:0] next_fwft_state;// = invalid; + + + + localparam FIFO_MEM_TYPE = FIFO_MEMORY_TYPE; + localparam RD_MODE = READ_MODE; + localparam ENABLE_ECC = (ECC_MODE == 1) ? 3 : 0; + localparam FIFO_READ_DEPTH = FIFO_WRITE_DEPTH*WRITE_DATA_WIDTH/READ_DATA_WIDTH; + localparam FIFO_SIZE = FIFO_WRITE_DEPTH*WRITE_DATA_WIDTH; + localparam WR_WIDTH_LOG = clog2(WRITE_DATA_WIDTH); + localparam WR_DEPTH_LOG = clog2(FIFO_WRITE_DEPTH); + localparam WR_PNTR_WIDTH = clog2(FIFO_WRITE_DEPTH); + localparam RD_PNTR_WIDTH = clog2(FIFO_READ_DEPTH); + localparam FULL_RST_VAL = FULL_RESET_VALUE == 0 ? 1'b0 : 1'b1; + localparam WR_RD_RATIO = (WR_PNTR_WIDTH > RD_PNTR_WIDTH) ? (WR_PNTR_WIDTH-RD_PNTR_WIDTH) : 0; + localparam READ_MODE_LL = (READ_MODE == 0) ? 0 : 1; + localparam PF_THRESH_ADJ = (READ_MODE == 0) ? PROG_FULL_THRESH : + PROG_FULL_THRESH - (2*(2**WR_RD_RATIO)); + localparam PE_THRESH_ADJ = (READ_MODE_LL == 1 && FIFO_MEMORY_TYPE != 4) ? PROG_EMPTY_THRESH - 2'h2 : PROG_EMPTY_THRESH; + + localparam PF_THRESH_MIN = 3+(READ_MODE_LL*2*(((FIFO_WRITE_DEPTH-1)/FIFO_READ_DEPTH)+1))+(COMMON_CLOCK?0:CDC_DEST_SYNC_FF); + localparam PF_THRESH_MAX = (FIFO_WRITE_DEPTH-3)-(READ_MODE_LL*2*(((FIFO_WRITE_DEPTH-1)/FIFO_READ_DEPTH)+1)); + localparam PE_THRESH_MIN = 3+(READ_MODE_LL*2); + localparam PE_THRESH_MAX = (FIFO_READ_DEPTH-3)-(READ_MODE_LL*2); + localparam WR_DC_WIDTH_EXT = clog2(FIFO_WRITE_DEPTH)+1; + localparam RD_DC_WIDTH_EXT = clog2(FIFO_READ_DEPTH)+1; + localparam RD_LATENCY = (READ_MODE == 2) ? 1 : (READ_MODE == 1) ? 2 : FIFO_READ_LATENCY; + localparam WIDTH_RATIO = (READ_DATA_WIDTH > WRITE_DATA_WIDTH) ? (READ_DATA_WIDTH/WRITE_DATA_WIDTH) : (WRITE_DATA_WIDTH/READ_DATA_WIDTH); + + localparam [15:0] EN_ADV_FEATURE = hstr2bin(USE_ADV_FEATURES); + + localparam EN_OF = EN_ADV_FEATURE[0]; //EN_ADV_FLAGS_WR[0] ? 1 : 0; + localparam EN_PF = EN_ADV_FEATURE[1]; //EN_ADV_FLAGS_WR[1] ? 1 : 0; + localparam EN_WDC = EN_ADV_FEATURE[2]; //EN_ADV_FLAGS_WR[2] ? 1 : 0; + localparam EN_AF = EN_ADV_FEATURE[3]; //EN_ADV_FLAGS_WR[3] ? 1 : 0; + localparam EN_WACK = EN_ADV_FEATURE[4]; //EN_ADV_FLAGS_WR[4] ? 1 : 0; + localparam FG_EQ_ASYM_DOUT = EN_ADV_FEATURE[5]; //EN_ADV_FLAGS_WR[5] ? 1 : 0; + localparam EN_UF = EN_ADV_FEATURE[8]; //EN_ADV_FLAGS_RD[0] ? 1 : 0; + localparam EN_PE = EN_ADV_FEATURE[9]; //EN_ADV_FLAGS_RD[1] ? 1 : 0; + localparam EN_RDC = EN_ADV_FEATURE[10]; //EN_ADV_FLAGS_RD[2] ? 1 : 0; + localparam EN_AE = EN_ADV_FEATURE[11]; //EN_ADV_FLAGS_RD[3] ? 1 : 0; + localparam EN_DVLD = EN_ADV_FEATURE[12]; //EN_ADV_FLAGS_RD[4] ? 1 : 0; + + wire wrst_busy; + wire [WR_PNTR_WIDTH-1:0] wr_pntr; + wire [WR_PNTR_WIDTH:0] wr_pntr_ext; + wire [WR_PNTR_WIDTH-1:0] wr_pntr_rd_cdc; + wire [WR_PNTR_WIDTH:0] wr_pntr_rd_cdc_dc; + wire [WR_PNTR_WIDTH-1:0] wr_pntr_rd; + wire [WR_PNTR_WIDTH:0] wr_pntr_rd_dc; + wire [WR_PNTR_WIDTH-1:0] rd_pntr_wr_adj; + wire [WR_PNTR_WIDTH:0] rd_pntr_wr_adj_dc; + wire [WR_PNTR_WIDTH-1:0] wr_pntr_plus1; + wire [WR_PNTR_WIDTH-1:0] wr_pntr_plus2; + wire [WR_PNTR_WIDTH-1:0] wr_pntr_plus3; + wire [WR_PNTR_WIDTH:0] wr_pntr_plus1_pf; + wire [WR_PNTR_WIDTH:0] rd_pntr_wr_adj_inv_pf; + reg [WR_PNTR_WIDTH:0] diff_pntr_pf_q = {WR_PNTR_WIDTH{1'b0}}; + wire [WR_PNTR_WIDTH-1:0] diff_pntr_pf; + wire [RD_PNTR_WIDTH-1:0] rd_pntr; + wire [RD_PNTR_WIDTH:0] rd_pntr_ext; + wire [RD_PNTR_WIDTH-1:0] rd_pntr_wr_cdc; + wire [RD_PNTR_WIDTH-1:0] rd_pntr_wr; + wire [RD_PNTR_WIDTH:0] rd_pntr_wr_cdc_dc; + wire [RD_PNTR_WIDTH:0] rd_pntr_wr_dc; + wire [RD_PNTR_WIDTH-1:0] wr_pntr_rd_adj; + wire [RD_PNTR_WIDTH:0] wr_pntr_rd_adj_dc; + wire [RD_PNTR_WIDTH-1:0] rd_pntr_plus1; + wire [RD_PNTR_WIDTH-1:0] rd_pntr_plus2; + wire invalid_state; + wire valid_fwft; + wire ram_valid_fwft; + wire going_empty; + wire leaving_empty; + wire going_aempty; + wire leaving_aempty; + reg ram_empty_i = 1'b1; + reg ram_aempty_i = 1'b1; + wire empty_i; + wire going_full; + wire leaving_full; + wire going_afull; + wire leaving_afull; + reg prog_full_i = FULL_RST_VAL; + reg ram_full_i = FULL_RST_VAL; + reg ram_afull_i = FULL_RST_VAL; + reg ram_full_n = ~FULL_RST_VAL; + wire ram_wr_en_i; + wire ram_rd_en_i; + reg wr_ack_i = 1'b0; + wire rd_en_i; + reg rd_en_fwft; + wire ram_regce; + wire ram_regce_pipe; + wire [READ_DATA_WIDTH-1:0] dout_i; + reg empty_fwft_i = 1'b1; + reg aempty_fwft_i = 1'b1; + reg empty_fwft_fb = 1'b1; + reg overflow_i = 1'b0; + reg underflow_i = 1'b0; + reg data_valid_fwft = 1'b0; + reg data_valid_std = 1'b0; + wire data_vld_std; + wire wrp_gt_rdp_and_red; + wire wrp_lt_rdp_and_red; + reg ram_wr_en_pf_q = 1'b0; + reg ram_rd_en_pf_q = 1'b0; + wire ram_wr_en_pf; + wire ram_rd_en_pf; + wire wr_pntr_plus1_pf_carry; + wire rd_pntr_wr_adj_pf_carry; + wire write_allow; + wire read_allow; + wire read_only; + wire write_only; + reg write_only_q; + reg read_only_q; + reg [RD_PNTR_WIDTH-1:0] diff_pntr_pe_reg1; + reg [RD_PNTR_WIDTH-1:0] diff_pntr_pe_reg2; + reg [RD_PNTR_WIDTH-1:0] diff_pntr_pe = 'b0; + reg prog_empty_i = 1'b1; + reg ram_empty_i_d1 = 1'b1; + wire fe_of_empty; + // function to validate the write depth value + function logic dpth_pwr_2; + input integer fifo_depth; + integer log2_of_depth; // correcponding to the default value of 2k depth + log2_of_depth = clog2(fifo_depth); + if (fifo_depth == 2 ** log2_of_depth) + dpth_pwr_2 = 1; + else + dpth_pwr_2 = 0; + return dpth_pwr_2; + endfunction + + initial begin : config_drc + reg drc_err_flag; + drc_err_flag = 0; + #1; + + if (COMMON_CLOCK == 0 && FIFO_MEM_TYPE == 3) begin + $error("[%s %0d-%0d] UltraRAM cannot be used as asynchronous FIFO because it has only one clock support %m", "XPM_FIFO", 1, 1); + drc_err_flag = 1; + end + + if (COMMON_CLOCK == 1 && RELATED_CLOCKS == 1) begin + $error("[%s %0d-%0d] Related Clocks cannot be used in synchronous FIFO because it is applicable only for asynchronous FIFO %m", "XPM_FIFO", 1, 2); + drc_err_flag = 1; + end + + if(!(FIFO_WRITE_DEPTH > 15 && FIFO_WRITE_DEPTH <= 4*1024*1024)) begin + $error("[%s %0d-%0d] FIFO_WRITE_DEPTH (%0d) value specified is not within the supported ranges. Miniumum supported depth is 16, and the maximum supported depth is 4*1024*1024 locations. %m", "XPM_FIFO", 1, 3, FIFO_WRITE_DEPTH); + drc_err_flag = 1; + end + + if(!dpth_pwr_2(FIFO_WRITE_DEPTH) && (FIFO_WRITE_DEPTH > 15 && FIFO_WRITE_DEPTH <= 4*1024*1024)) begin + $error("[%s %0d-%0d] FIFO_WRITE_DEPTH (%0d) value specified is non-power of 2, but this release of XPM_FIFO supports configurations having the fifo write depth set to power of 2. %m", "XPM_FIFO", 1, 4, FIFO_WRITE_DEPTH); + drc_err_flag = 1; + end + + if (CDC_DEST_SYNC_FF < 2 || CDC_DEST_SYNC_FF > 8) begin + $error("[%s %0d-%0d] CDC_DEST_SYNC_FF (%0d) value is specified for this configuration, but this beta release of XPM_FIFO supports CDC_DEST_SYNC_FF values in between 2 and 8. %m", "XPM_FIFO", 1, 5,CDC_DEST_SYNC_FF); + drc_err_flag = 1; + end + if (CDC_DEST_SYNC_FF != 2 && RELATED_CLOCKS == 1) begin + $error("[%s %0d-%0d] CDC_DEST_SYNC_FF (%0d) value is specified for this configuration, but CDC_DEST_SYNC_FF value can not be modified from default value when RELATED_CLOCKS parameter is set to 1. %m", "XPM_FIFO", 1, 6,CDC_DEST_SYNC_FF); + drc_err_flag = 1; + end + if (FIFO_WRITE_DEPTH == 16 && CDC_DEST_SYNC_FF > 4) begin + $error("[%s %0d-%0d] CDC_DEST_SYNC_FF = %0d and FIFO_WRITE_DEPTH = %0d. This is invalid combination. Either FIFO_WRITE_DEPTH should be increased or CDC_DEST_SYNC_FF should be reduced. %m", "XPM_FIFO", 1, 7,CDC_DEST_SYNC_FF, FIFO_WRITE_DEPTH); + drc_err_flag = 1; + end + if (EN_ADV_FEATURE[7:5] != 3'h0) begin + $error("[%s %0d-%0d] USE_ADV_FEATURES[7:5] = %0h. This is a reserved field and must be set to 0s. %m", "XPM_FIFO", 1, 8, EN_ADV_FEATURE[7:5]); + drc_err_flag = 1; + end + if (EN_ADV_FEATURE[15:14] != 3'h0) begin + $error("[%s %0d-%0d] USE_ADV_FEATURES[15:13] = %0h. This is a reserved field and must be set to 0s. %m", "XPM_FIFO", 1, 9, EN_ADV_FEATURE[15:13]); + drc_err_flag = 1; + end +// if(WIDTH_RATIO > 32) begin +// $error("[%s %0d-%0d] The ratio between WRITE_DATA_WIDTH (%0d) and READ_DATA_WIDTH (%0d) is greater than 32, but this release of XPM_FIFO supports configurations having the ratio between data widths must be less than 32. %m", "XPM_FIFO", 1, 10, WRITE_DATA_WIDTH, READ_DATA_WIDTH); +// drc_err_flag = 1; +// end + if (WR_WIDTH_LOG+WR_DEPTH_LOG > 30) begin + $error("[%s %0d-%0d] The specified Width(%0d) and Depth(%0d) exceeds the maximum supported FIFO SIZE. Please reduce either FIFO Width or Depth. %m", "XPM_FIFO", 1, 10, WRITE_DATA_WIDTH,FIFO_WRITE_DEPTH); + drc_err_flag = 1; + end + if(FIFO_READ_DEPTH < 16) begin + $error("[%s %0d-%0d] Write Width is %0d Read Width is %0d and Write Depth is %0d, this results in the Read Depth(%0d) less than 16. This is an invalid combination, Ensure the depth on both sides is minimum 16. %m", "XPM_FIFO", 1, 11, WRITE_DATA_WIDTH, READ_DATA_WIDTH, FIFO_WRITE_DEPTH, FIFO_READ_DEPTH); + drc_err_flag = 1; + end + + // Range Checks + if (COMMON_CLOCK > 1) begin + $error("[%s %0d-%0d] COMMON_CLOCK (%s) value is outside of legal range. %m", "XPM_FIFO", 10, 1, COMMON_CLOCK); + drc_err_flag = 1; + end + if (FIFO_MEMORY_TYPE > 3) begin + $error("[%s %0d-%0d] FIFO_MEMORY_TYPE (%s) value is outside of legal range. %m", "XPM_FIFO", 10, 2, FIFO_MEMORY_TYPE); + drc_err_flag = 1; + end + if (READ_MODE > 2) begin + $error("[%s %0d-%0d] READ_MODE (%s) value is outside of legal range. %m", "XPM_FIFO", 10, 3, READ_MODE); + drc_err_flag = 1; + end + + if (ECC_MODE > 1) begin + $error("[%s %0d-%0d] ECC_MODE (%s) value is outside of legal range. %m", "XPM_FIFO", 10, 4, ECC_MODE); + drc_err_flag = 1; + end + if (!(WAKEUP_TIME == 0 || WAKEUP_TIME == 2)) begin + $error("[%s %0d-%0d] WAKEUP_TIME (%0d) value is outside of legal range. WAKEUP_TIME should be either 0 or 2. %m", "XPM_FIFO", 10, 5, WAKEUP_TIME); + drc_err_flag = 1; + end + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of legal range. %m", "XPM_FIFO", 10, 6, VERSION); + drc_err_flag = 1; + end + + if (!(WRITE_DATA_WIDTH > 0)) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH (%0d) value is outside of legal range. %m", "XPM_FIFO", 15, 2, WRITE_DATA_WIDTH); + drc_err_flag = 1; + end + if (!(READ_DATA_WIDTH > 0)) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH (%0d) value is outside of legal range. %m", "XPM_FIFO", 15, 3, READ_DATA_WIDTH); + drc_err_flag = 1; + end + + if (EN_PF == 1 && ((PROG_FULL_THRESH < PF_THRESH_MIN) || (PROG_FULL_THRESH > PF_THRESH_MAX))) begin + $error("[%s %0d-%0d] Programmable Full flag is enabled, but PROG_FULL_THRESH (%0d) value is outside of legal range. PROG_FULL_THRESH value must be between %0d and %0d. %m", "XPM_FIFO", 15, 4, PROG_FULL_THRESH, PF_THRESH_MIN, PF_THRESH_MAX); + drc_err_flag = 1; + end + + if (EN_PE == 1 && (WIDTH_RATIO <= 32) && ((PROG_EMPTY_THRESH < PE_THRESH_MIN) || (PROG_EMPTY_THRESH > PE_THRESH_MAX))) begin + $error("[%s %0d-%0d] Programmable Empty flag is enabled, but PROG_EMPTY_THRESH (%0d) value is outside of legal range. PROG_EMPTY_THRESH value must be between %0d and %0d. %m", "XPM_FIFO", 15, 5, PROG_EMPTY_THRESH, PE_THRESH_MIN, PE_THRESH_MAX); + drc_err_flag = 1; + end + + if (EN_WDC == 1 && ((WR_DATA_COUNT_WIDTH < 0) || (WR_DATA_COUNT_WIDTH > WR_DC_WIDTH_EXT))) begin + $error("[%s %0d-%0d] Write Data Count is enabled, but WR_DATA_COUNT_WIDTH (%0d) value is outside of legal range. WR_DATA_COUNT_WIDTH value must be between %0d and %0d. %m", "XPM_FIFO", 15, 6, WR_DATA_COUNT_WIDTH, 0, WR_DC_WIDTH_EXT); + drc_err_flag = 1; + end + + + if (EN_RDC == 1 && ((RD_DATA_COUNT_WIDTH < 0) || (RD_DATA_COUNT_WIDTH > RD_DC_WIDTH_EXT))) begin + $error("[%s %0d-%0d] Read Data Count is enabled, but RD_DATA_COUNT_WIDTH (%0d) value is outside of legal range. RD_DATA_COUNT_WIDTH value must be between %0d and %0d. %m", "XPM_FIFO", 15, 7, RD_DATA_COUNT_WIDTH, 0, RD_DC_WIDTH_EXT); + drc_err_flag = 1; + end + + //DRCs on Low Latency FWFT mode + if (READ_MODE == 2 && FIFO_MEMORY_TYPE != 1) begin + $error("[%s %0d-%0d] XPM_FIFO does not support Read Mode (Low Latency FWFT) for FIFO_MEMORY_TYPE other than lutram/distributed. %m", "XPM_FIFO", 16, 2); + drc_err_flag = 1; + end + if (READ_MODE == 2 && EN_ADV_FEATURE != 16'h0) begin + $error("[%s %0d-%0d] USE_ADV_FEATURES = %0h. XPM_FIFO does not support Advanced Features in Low Latency FWFT mode. %m", "XPM_FIFO", 16, 3, EN_ADV_FEATURE); + drc_err_flag = 1; + end + + // Infos + + // Warnings + if (drc_err_flag == 1) + #1 $finish; + end : config_drc + + wire wr_en_i; + wire wr_rst_i; + wire rd_rst_i; + reg rd_rst_d2 = 1'b0; + wire rst_d1; + wire rst_d2; + wire clr_full; + wire empty_fwft_d1; + wire leaving_empty_fwft_fe; + wire leaving_empty_fwft_re; + wire le_fwft_re; + wire le_fwft_fe; + wire [1:0] extra_words_fwft; + wire le_fwft_re_wr; + wire le_fwft_fe_wr; + + generate + + xpm_fifo_rst # (COMMON_CLOCK, CDC_DEST_SYNC_FF, SIM_ASSERT_CHK) + xpm_fifo_rst_inst (rst, wr_clk, rd_clk, wr_rst_i, rd_rst_i, wrst_busy, rd_rst_busy); + assign wr_rst_busy = wrst_busy | rst_d1; + + xpm_fifo_reg_bit #(0) + rst_d1_inst (1'b0, wr_clk, wrst_busy, rst_d1); + xpm_fifo_reg_bit #(0) + rst_d2_inst (1'b0, wr_clk, rst_d1, rst_d2); + + assign clr_full = ~wrst_busy & rst_d1 & ~rst; + assign rd_en_i = (RD_MODE == 0) ? rd_en : rd_en_fwft; + + if (REMOVE_WR_RD_PROT_LOGIC == 1) begin : ngen_wr_rd_prot + assign ram_wr_en_i = wr_en; + assign ram_rd_en_i = rd_en_i; + end : ngen_wr_rd_prot + else begin : gen_wr_rd_prot + assign ram_wr_en_i = wr_en & ~ram_full_i & ~(wrst_busy|rst_d1); + assign ram_rd_en_i = rd_en_i & ~ram_empty_i; + end : gen_wr_rd_prot + + // Write pointer generation + xpm_counter_updn # (WR_PNTR_WIDTH+1, 0) + wrp_inst (wrst_busy, wr_clk, ram_wr_en_i, ram_wr_en_i, 1'b0, wr_pntr_ext); + assign wr_pntr = wr_pntr_ext[WR_PNTR_WIDTH-1:0]; + + xpm_counter_updn # (WR_PNTR_WIDTH, 1) + wrpp1_inst (wrst_busy, wr_clk, ram_wr_en_i, ram_wr_en_i, 1'b0, wr_pntr_plus1); + + xpm_counter_updn # (WR_PNTR_WIDTH, 2) + wrpp2_inst (wrst_busy, wr_clk, ram_wr_en_i, ram_wr_en_i, 1'b0, wr_pntr_plus2); + + if (EN_AF == 1) begin : gaf_wptr_p3 + xpm_counter_updn # (WR_PNTR_WIDTH, 3) + wrpp3_inst (wrst_busy, wr_clk, ram_wr_en_i, ram_wr_en_i, 1'b0, wr_pntr_plus3); + end : gaf_wptr_p3 + + // Read pointer generation + xpm_counter_updn # (RD_PNTR_WIDTH+1, 0) + rdp_inst (rd_rst_i, rd_clk, ram_rd_en_i, ram_rd_en_i, 1'b0, rd_pntr_ext); + assign rd_pntr = rd_pntr_ext[RD_PNTR_WIDTH-1:0]; + + xpm_counter_updn # (RD_PNTR_WIDTH, 1) + rdpp1_inst (rd_rst_i, rd_clk, ram_rd_en_i, ram_rd_en_i, 1'b0, rd_pntr_plus1); + + if (EN_AE == 1) begin : gae_rptr_p2 + xpm_counter_updn # (RD_PNTR_WIDTH, 2) + rdpp2_inst (rd_rst_i, rd_clk, ram_rd_en_i, ram_rd_en_i, 1'b0, rd_pntr_plus2); + end : gae_rptr_p2 + + assign full = ram_full_i; + assign full_n = ram_full_n; + assign almost_full = EN_AF == 1 ? ram_afull_i : 1'b0; + assign wr_ack = EN_WACK == 1 ? wr_ack_i : 1'b0; + if (EN_WACK == 1) begin : gwack + always @ (posedge wr_clk) begin + if (rst | wr_rst_i | wrst_busy) + wr_ack_i <= 1'b0; + else + wr_ack_i <= ram_wr_en_i; + end + end : gwack + + assign prog_full = EN_PF == 1 ? (PROG_FULL_THRESH > 0) ? prog_full_i : 1'b0 : 1'b0; + assign prog_empty = EN_PE == 1 ? (PROG_EMPTY_THRESH > 0) ? prog_empty_i : 1'b1 : 1'b0; + + assign empty_i = (RD_MODE == 0)? ram_empty_i : empty_fwft_i; + assign empty = empty_i; + assign almost_empty = EN_AE == 1 ? (RD_MODE == 0) ? ram_aempty_i : aempty_fwft_i : 1'b0; + + assign data_valid = EN_DVLD == 1 ? (RD_MODE == 0) ? data_valid_std : data_valid_fwft : 1'b0; + if (EN_DVLD == 1) begin : gdvld + assign data_vld_std = (RD_MODE == 0) ? (FIFO_READ_LATENCY == 1) ? ram_rd_en_i: ram_regce_pipe : ram_regce; + always @ (posedge rd_clk) begin + if (rd_rst_i) + data_valid_std <= 1'b0; + else + data_valid_std <= data_vld_std; + end + end : gdvld + + // Simple dual port RAM instantiation for non-Built-in FIFO + if (FIFO_MEMORY_TYPE < 4) begin : gen_sdpram + + // Reset is not supported when ECC is enabled by the BRAM/URAM primitives + wire rst_int; + if(ECC_MODE !=0) begin : gnd_rst + assign rst_int = 0; + end : gnd_rst + else begin : rst_gen + assign rst_int = rd_rst_i; + end : rst_gen + // ---------------------------------------------------------------------- + // Base module instantiation with simple dual port RAM configuration + // ---------------------------------------------------------------------- + localparam USE_DRAM_CONSTRAINT = (COMMON_CLOCK == 0 && FIFO_MEMORY_TYPE == 1) ? 1 : 0; + localparam WR_MODE_B = (FIFO_MEMORY_TYPE == 1 || FIFO_MEMORY_TYPE == 3) ? 1 : 2; + xpm_memory_base # ( + + // Common module parameters + .MEMORY_TYPE (1 ), + .MEMORY_SIZE (FIFO_SIZE ), + .MEMORY_PRIMITIVE (FIFO_MEMORY_TYPE ), + .CLOCKING_MODE (COMMON_CLOCK ? 0 : 1 ), + .ECC_MODE (ENABLE_ECC ), + .USE_MEM_INIT (0 ), + .MEMORY_INIT_FILE ("none" ), + .MEMORY_INIT_PARAM ("" ), + .WAKEUP_TIME (WAKEUP_TIME ), + .MESSAGE_CONTROL (0 ), + .VERSION (0 ), + .MEMORY_OPTIMIZATION ("true" ), + .AUTO_SLEEP_TIME (0 ), + .USE_EMBEDDED_CONSTRAINT (USE_DRAM_CONSTRAINT ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + + // Port A module parameters + .WRITE_DATA_WIDTH_A (WRITE_DATA_WIDTH ), + .READ_DATA_WIDTH_A (WRITE_DATA_WIDTH ), + .BYTE_WRITE_WIDTH_A (WRITE_DATA_WIDTH ), + .ADDR_WIDTH_A (WR_PNTR_WIDTH ), + .READ_RESET_VALUE_A ("0" ), + .READ_LATENCY_A (2 ), + .WRITE_MODE_A (2 ), + + // Port B module parameters + .WRITE_DATA_WIDTH_B (READ_DATA_WIDTH ), + .READ_DATA_WIDTH_B (READ_DATA_WIDTH ), + .BYTE_WRITE_WIDTH_B (READ_DATA_WIDTH ), + .ADDR_WIDTH_B (RD_PNTR_WIDTH ), + .READ_RESET_VALUE_B (DOUT_RESET_VALUE ), + .READ_LATENCY_B (RD_LATENCY ), + .WRITE_MODE_B (WR_MODE_B ) + ) xpm_memory_base_inst ( + + // Common module ports + .sleep (sleep ), + + // Port A module ports + .clka (wr_clk ), + .rsta (1'b0 ), + .ena (ram_wr_en_i ), + .regcea (1'b0 ), + .wea (ram_wr_en_i ), + .addra (wr_pntr ), + .dina (din ), + .injectsbiterra (injectsbiterr ), + .injectdbiterra (injectdbiterr ), + .douta ( ), + .sbiterra ( ), + .dbiterra ( ), + + // Port B module ports + .clkb (rd_clk ), + .rstb (rst_int ), + .enb (ram_rd_en_i ), + .regceb (READ_MODE == 0 ? ram_regce_pipe: ram_regce), + .web (1'b0 ), + .addrb (rd_pntr ), + .dinb ({READ_DATA_WIDTH{1'b0}} ), + .injectsbiterrb (1'b0 ), + .injectdbiterrb (1'b0 ), + .doutb (dout_i ), + .sbiterrb (sbiterr ), + .dbiterrb (dbiterr ) + ); + end : gen_sdpram + + if (WR_PNTR_WIDTH == RD_PNTR_WIDTH) begin : wrp_eq_rdp + assign wr_pntr_rd_adj = wr_pntr_rd[WR_PNTR_WIDTH-1:WR_PNTR_WIDTH-RD_PNTR_WIDTH]; + assign wr_pntr_rd_adj_dc = wr_pntr_rd_dc[WR_PNTR_WIDTH:WR_PNTR_WIDTH-RD_PNTR_WIDTH]; + assign rd_pntr_wr_adj = rd_pntr_wr[RD_PNTR_WIDTH-1:RD_PNTR_WIDTH-WR_PNTR_WIDTH]; + assign rd_pntr_wr_adj_dc = rd_pntr_wr_dc[RD_PNTR_WIDTH:RD_PNTR_WIDTH-WR_PNTR_WIDTH]; + end : wrp_eq_rdp + + if (WR_PNTR_WIDTH > RD_PNTR_WIDTH) begin : wrp_gt_rdp + assign wr_pntr_rd_adj = wr_pntr_rd[WR_PNTR_WIDTH-1:WR_PNTR_WIDTH-RD_PNTR_WIDTH]; + assign wr_pntr_rd_adj_dc = wr_pntr_rd_dc[WR_PNTR_WIDTH:WR_PNTR_WIDTH-RD_PNTR_WIDTH]; + assign rd_pntr_wr_adj[WR_PNTR_WIDTH-1:WR_PNTR_WIDTH-RD_PNTR_WIDTH] = rd_pntr_wr; + assign rd_pntr_wr_adj[WR_PNTR_WIDTH-RD_PNTR_WIDTH-1:0] = {(WR_PNTR_WIDTH-RD_PNTR_WIDTH){1'b0}}; + assign rd_pntr_wr_adj_dc[WR_PNTR_WIDTH:WR_PNTR_WIDTH-RD_PNTR_WIDTH] = rd_pntr_wr_dc; + assign rd_pntr_wr_adj_dc[WR_PNTR_WIDTH-RD_PNTR_WIDTH-1:0] = {(WR_PNTR_WIDTH-RD_PNTR_WIDTH){1'b0}}; + end : wrp_gt_rdp + + if (WR_PNTR_WIDTH < RD_PNTR_WIDTH) begin : wrp_lt_rdp + assign wr_pntr_rd_adj[RD_PNTR_WIDTH-1:RD_PNTR_WIDTH-WR_PNTR_WIDTH] = wr_pntr_rd; + assign wr_pntr_rd_adj[RD_PNTR_WIDTH-WR_PNTR_WIDTH-1:0] = {(RD_PNTR_WIDTH-WR_PNTR_WIDTH){1'b0}}; + assign wr_pntr_rd_adj_dc[RD_PNTR_WIDTH:RD_PNTR_WIDTH-WR_PNTR_WIDTH] = wr_pntr_rd_dc; + assign wr_pntr_rd_adj_dc[RD_PNTR_WIDTH-WR_PNTR_WIDTH-1:0] = {(RD_PNTR_WIDTH-WR_PNTR_WIDTH){1'b0}}; + assign rd_pntr_wr_adj = rd_pntr_wr[RD_PNTR_WIDTH-1:RD_PNTR_WIDTH-WR_PNTR_WIDTH]; + assign rd_pntr_wr_adj_dc = rd_pntr_wr_dc[RD_PNTR_WIDTH:RD_PNTR_WIDTH-WR_PNTR_WIDTH]; + end : wrp_lt_rdp + + if (COMMON_CLOCK == 0 && RELATED_CLOCKS == 0) begin : gen_cdc_pntr + // Synchronize the write pointer in rd_clk domain + xpm_cdc_gray #( + .DEST_SYNC_FF (CDC_DEST_SYNC_FF), + .INIT_SYNC_FF (1), + .WIDTH (WR_PNTR_WIDTH)) + + wr_pntr_cdc_inst ( + .src_clk (wr_clk), + .src_in_bin (wr_pntr), + .dest_clk (rd_clk), + .dest_out_bin (wr_pntr_rd_cdc)); + + // Register the output of XPM_CDC_GRAY on read side + xpm_fifo_reg_vec #(WR_PNTR_WIDTH) + wpr_gray_reg (rd_rst_i, rd_clk, wr_pntr_rd_cdc, wr_pntr_rd); + + // Synchronize the extended write pointer in rd_clk domain + xpm_cdc_gray #( + .DEST_SYNC_FF (READ_MODE == 0 ? CDC_DEST_SYNC_FF : CDC_DEST_SYNC_FF+2), + .INIT_SYNC_FF (1), + .WIDTH (WR_PNTR_WIDTH+1)) + wr_pntr_cdc_dc_inst ( + .src_clk (wr_clk), + .src_in_bin (wr_pntr_ext), + .dest_clk (rd_clk), + .dest_out_bin (wr_pntr_rd_cdc_dc)); + + // Register the output of XPM_CDC_GRAY on read side + xpm_fifo_reg_vec #(WR_PNTR_WIDTH+1) + wpr_gray_reg_dc (rd_rst_i, rd_clk, wr_pntr_rd_cdc_dc, wr_pntr_rd_dc); + + // Synchronize the read pointer in wr_clk domain + xpm_cdc_gray #( + .DEST_SYNC_FF (CDC_DEST_SYNC_FF), + .INIT_SYNC_FF (1), + .WIDTH (RD_PNTR_WIDTH)) + rd_pntr_cdc_inst ( + .src_clk (rd_clk), + .src_in_bin (rd_pntr), + .dest_clk (wr_clk), + .dest_out_bin (rd_pntr_wr_cdc)); + + // Register the output of XPM_CDC_GRAY on write side + xpm_fifo_reg_vec #(RD_PNTR_WIDTH) + rpw_gray_reg (wrst_busy, wr_clk, rd_pntr_wr_cdc, rd_pntr_wr); + + // Synchronize the read pointer, subtracted by the extra word read for FWFT, in wr_clk domain + xpm_cdc_gray #( + .DEST_SYNC_FF (CDC_DEST_SYNC_FF), + .INIT_SYNC_FF (1), + .WIDTH (RD_PNTR_WIDTH+1)) + rd_pntr_cdc_dc_inst ( + .src_clk (rd_clk), + .src_in_bin (rd_pntr_ext-extra_words_fwft), + .dest_clk (wr_clk), + .dest_out_bin (rd_pntr_wr_cdc_dc)); + + // Register the output of XPM_CDC_GRAY on write side + xpm_fifo_reg_vec #(RD_PNTR_WIDTH+1) + rpw_gray_reg_dc (wrst_busy, wr_clk, rd_pntr_wr_cdc_dc, rd_pntr_wr_dc); + + end : gen_cdc_pntr + + if (RELATED_CLOCKS == 1) begin : gen_pntr_pf_rc + xpm_fifo_reg_vec #(RD_PNTR_WIDTH) + rpw_rc_reg (wrst_busy, wr_clk, rd_pntr, rd_pntr_wr); + + xpm_fifo_reg_vec #(WR_PNTR_WIDTH) + wpr_rc_reg (rd_rst_i, rd_clk, wr_pntr, wr_pntr_rd); + + xpm_fifo_reg_vec #(WR_PNTR_WIDTH+1) + wpr_rc_reg_dc (rd_rst_i, rd_clk, wr_pntr_ext, wr_pntr_rd_dc); + + xpm_fifo_reg_vec #(RD_PNTR_WIDTH+1) + rpw_rc_reg_dc (wrst_busy, wr_clk, (rd_pntr_ext-extra_words_fwft), rd_pntr_wr_dc); + end : gen_pntr_pf_rc + + if (COMMON_CLOCK == 0 || RELATED_CLOCKS == 1) begin : gen_pf_ic_rc + + assign going_empty = ((wr_pntr_rd_adj == rd_pntr_plus1) & ram_rd_en_i); + assign leaving_empty = ((wr_pntr_rd_adj == rd_pntr)); + assign going_aempty = ((wr_pntr_rd_adj == rd_pntr_plus2) & ram_rd_en_i); + assign leaving_aempty = ((wr_pntr_rd_adj == rd_pntr_plus1)); + + assign going_full = ((rd_pntr_wr_adj == wr_pntr_plus2) & ram_wr_en_i); + assign leaving_full = ((rd_pntr_wr_adj == wr_pntr_plus1)); + assign going_afull = ((rd_pntr_wr_adj == wr_pntr_plus3) & ram_wr_en_i); + assign leaving_afull = ((rd_pntr_wr_adj == wr_pntr_plus2)); + + // Empty flag generation + always @ (posedge rd_clk) begin + if (rd_rst_i) begin + ram_empty_i <= 1'b1; + end else begin + ram_empty_i <= going_empty | leaving_empty; + end + end + + if (EN_AE == 1) begin : gae_ic_std + always @ (posedge rd_clk) begin + if (rd_rst_i) begin + ram_aempty_i <= 1'b1; + end else if (~ram_empty_i) begin + ram_aempty_i <= going_aempty | leaving_aempty; + end + end + end : gae_ic_std + + // Full flag generation + if (FULL_RST_VAL == 1) begin : gen_full_rst_val + always @ (posedge wr_clk) begin + if (wrst_busy) begin + ram_full_i <= FULL_RST_VAL; + ram_full_n <= ~FULL_RST_VAL; + end else begin + if (clr_full) begin + ram_full_i <= 1'b0; + ram_full_n <= 1'b1; + end else begin + ram_full_i <= going_full | leaving_full; + ram_full_n <= ~(going_full | leaving_full); + end + end + end + end : gen_full_rst_val + else begin : ngen_full_rst_val + always @ (posedge wr_clk) begin + if (wrst_busy) begin + ram_full_i <= 1'b0; + ram_full_n <= 1'b1; + end else begin + ram_full_i <= going_full | leaving_full; + ram_full_n <= ~(going_full | leaving_full); + end + end + end : ngen_full_rst_val + + if (EN_AF == 1) begin : gaf_ic + always @ (posedge wr_clk) begin + if (wrst_busy) begin + ram_afull_i <= FULL_RST_VAL; + end else if (~rst) begin + if (clr_full) begin + ram_afull_i <= 1'b0; + end else if (~ram_full_i) begin + ram_afull_i <= going_afull | leaving_afull; + end + end + end + end : gaf_ic + + // synthesis translate_off + `ifndef DISABLE_XPM_ASSERTIONS + if (SIM_ASSERT_CHK == 1) begin: assert_wr_rd_en + always @ (posedge rd_clk) begin + assert (!$isunknown(rd_en)) else $warning ("Input port 'rd_en' has unknown value 'X' or 'Z' at %0t. This may cause full/empty to be 'X' or 'Z' in simulation. Ensure 'rd_en' has a valid value ('0' or '1')",$time); + end + + always @ (posedge wr_clk) begin + assert (!$isunknown(wr_en)) else $warning ("Input port 'wr_en' has unknown value 'X' or 'Z' at %0t. This may cause full/empty to be 'X' or 'Z' in simulation. Ensure 'wr_en' has a valid value ('0' or '1')",$time); + end + + always @ (posedge wr_clk) begin + assert (!$isunknown(wr_en)) else $warning ("Input port 'wr_en' has unknown value 'X' or 'Z' at %0t. This may cause full/empty to be 'X' or 'Z' in simulation. Ensure 'wr_en' has a valid value ('0' or '1')",$time); + end + + end : assert_wr_rd_en + `endif + // synthesis translate_on + + // Programmable Full flag generation + if (EN_PF == 1) begin : gpf_ic + assign wr_pntr_plus1_pf = {wr_pntr_plus1,wr_pntr_plus1_pf_carry}; + assign rd_pntr_wr_adj_inv_pf = {~rd_pntr_wr_adj,rd_pntr_wr_adj_pf_carry}; + + // PF carry generation + assign wr_pntr_plus1_pf_carry = ram_wr_en_i; + assign rd_pntr_wr_adj_pf_carry = ram_wr_en_i; + + // PF diff pointer generation + always @ (posedge wr_clk) begin + if (wrst_busy) + diff_pntr_pf_q <= {WR_PNTR_WIDTH{1'b0}}; + else + diff_pntr_pf_q <= wr_pntr_plus1_pf + rd_pntr_wr_adj_inv_pf; + end + assign diff_pntr_pf = diff_pntr_pf_q[WR_PNTR_WIDTH:1]; + + always @ (posedge wr_clk) begin + if (wrst_busy) + prog_full_i <= FULL_RST_VAL; + else if (clr_full) + prog_full_i <= 1'b0; + else if (~ram_full_i) begin + if (diff_pntr_pf >= PF_THRESH_ADJ) + prog_full_i <= 1'b1; + else + prog_full_i <= 1'b0; + end else + prog_full_i <= prog_full_i; + end + end : gpf_ic + + /********************************************************* + * Programmable EMPTY flags + *********************************************************/ + //Determine the Assert and Negate thresholds for Programmable Empty + if (EN_PE == 1) begin : gpe_ic + + always @(posedge rd_clk) begin + if (rd_rst_i) begin + diff_pntr_pe <= 0; + prog_empty_i <= 1'b1; + end else begin + if (ram_rd_en_i) + diff_pntr_pe <= (wr_pntr_rd_adj - rd_pntr) - 1'h1; + else + diff_pntr_pe <= (wr_pntr_rd_adj - rd_pntr); + + if (~empty_i) begin + if (diff_pntr_pe <= PE_THRESH_ADJ) + prog_empty_i <= 1'b1; + else + prog_empty_i <= 1'b0; + end else + prog_empty_i <= prog_empty_i; + end + end + end : gpe_ic + end : gen_pf_ic_rc + + if (COMMON_CLOCK == 1 && RELATED_CLOCKS == 0) begin : gen_pntr_flags_cc + assign wr_pntr_rd = wr_pntr; + assign rd_pntr_wr = rd_pntr; + assign wr_pntr_rd_dc = wr_pntr_ext; + assign rd_pntr_wr_dc = rd_pntr_ext-extra_words_fwft; + assign write_allow = ram_wr_en_i & ~ram_full_i; + assign read_allow = ram_rd_en_i & ~empty_i; + + if (WR_PNTR_WIDTH == RD_PNTR_WIDTH) begin : wrp_eq_rdp + assign ram_wr_en_pf = ram_wr_en_i; + assign ram_rd_en_pf = ram_rd_en_i; + + assign going_empty = ((wr_pntr_rd_adj == rd_pntr_plus1) & ~ram_wr_en_i & ram_rd_en_i); + assign leaving_empty = ((wr_pntr_rd_adj == rd_pntr) & ram_wr_en_i); + assign going_aempty = ((wr_pntr_rd_adj == rd_pntr_plus2) & ~ram_wr_en_i & ram_rd_en_i); + assign leaving_aempty = ((wr_pntr_rd_adj == rd_pntr_plus1) & ram_wr_en_i & ~ram_rd_en_i); + + assign going_full = ((rd_pntr_wr_adj == wr_pntr_plus1) & ram_wr_en_i & ~ram_rd_en_i); + assign leaving_full = ((rd_pntr_wr_adj == wr_pntr) & ram_rd_en_i); + assign going_afull = ((rd_pntr_wr_adj == wr_pntr_plus2) & ram_wr_en_i & ~ram_rd_en_i); + assign leaving_afull = ((rd_pntr_wr_adj == wr_pntr_plus1) & ram_rd_en_i & ~ram_wr_en_i); + + assign write_only = write_allow & ~read_allow; + assign read_only = read_allow & ~write_allow; + + end : wrp_eq_rdp + + if (WR_PNTR_WIDTH > RD_PNTR_WIDTH) begin : wrp_gt_rdp + assign wrp_gt_rdp_and_red = &wr_pntr_rd[WR_PNTR_WIDTH-RD_PNTR_WIDTH-1:0]; + + assign going_empty = ((wr_pntr_rd_adj == rd_pntr_plus1) & ~(ram_wr_en_i & wrp_gt_rdp_and_red) & ram_rd_en_i); + assign leaving_empty = ((wr_pntr_rd_adj == rd_pntr) & (ram_wr_en_i & wrp_gt_rdp_and_red)); + assign going_aempty = ((wr_pntr_rd_adj == rd_pntr_plus2) & ~(ram_wr_en_i & wrp_gt_rdp_and_red) & ram_rd_en_i); + assign leaving_aempty = ((wr_pntr_rd_adj == rd_pntr_plus1) & (ram_wr_en_i & wrp_gt_rdp_and_red) & ~ram_rd_en_i); + + assign going_full = ((rd_pntr_wr_adj == wr_pntr_plus1) & ram_wr_en_i & ~ram_rd_en_i); + assign leaving_full = ((rd_pntr_wr_adj == wr_pntr) & ram_rd_en_i); + assign going_afull = ((rd_pntr_wr_adj == wr_pntr_plus2) & ram_wr_en_i & ~ram_rd_en_i); + assign leaving_afull = (((rd_pntr_wr_adj == wr_pntr) | (rd_pntr_wr_adj == wr_pntr_plus1) | (rd_pntr_wr_adj == wr_pntr_plus2)) & ram_rd_en_i); + + assign ram_wr_en_pf = ram_wr_en_i & wrp_gt_rdp_and_red; + assign ram_rd_en_pf = ram_rd_en_i; + + assign read_only = read_allow & (~(write_allow & (&wr_pntr[WR_PNTR_WIDTH-RD_PNTR_WIDTH-1 : 0]))); + assign write_only = write_allow & (&wr_pntr[WR_PNTR_WIDTH-RD_PNTR_WIDTH-1 : 0]) & ~read_allow; + + + end : wrp_gt_rdp + + if (WR_PNTR_WIDTH < RD_PNTR_WIDTH) begin : wrp_lt_rdp + assign wrp_lt_rdp_and_red = &rd_pntr_wr[RD_PNTR_WIDTH-WR_PNTR_WIDTH-1:0]; + + assign going_empty = ((wr_pntr_rd_adj == rd_pntr_plus1) & ~ram_wr_en_i & ram_rd_en_i); + assign leaving_empty = ((wr_pntr_rd_adj == rd_pntr) & ram_wr_en_i); + assign going_aempty = ((wr_pntr_rd_adj == rd_pntr_plus2) & ~ram_wr_en_i & ram_rd_en_i); + assign leaving_aempty = (((wr_pntr_rd_adj == rd_pntr) | (wr_pntr_rd_adj == rd_pntr_plus1) | (wr_pntr_rd_adj == rd_pntr_plus2)) & ram_wr_en_i); + + assign going_full = ((rd_pntr_wr_adj == wr_pntr_plus1) & ~(ram_rd_en_i & wrp_lt_rdp_and_red) & ram_wr_en_i); + assign leaving_full = ((rd_pntr_wr_adj == wr_pntr) & (ram_rd_en_i & wrp_lt_rdp_and_red)); + assign going_afull = ((rd_pntr_wr_adj == wr_pntr_plus2) & ~(ram_rd_en_i & wrp_lt_rdp_and_red) & ram_wr_en_i); + assign leaving_afull = ((rd_pntr_wr_adj == wr_pntr_plus1) & ~ram_wr_en_i & (ram_rd_en_i & wrp_lt_rdp_and_red)); + + assign ram_wr_en_pf = ram_wr_en_i; + assign ram_rd_en_pf = ram_rd_en_i & wrp_lt_rdp_and_red; + + assign read_only = read_allow & (&rd_pntr[RD_PNTR_WIDTH-WR_PNTR_WIDTH-1 : 0]) & ~write_allow; + assign write_only = write_allow & (~(read_allow & (&rd_pntr[RD_PNTR_WIDTH-WR_PNTR_WIDTH-1 : 0]))); + end : wrp_lt_rdp + + // Empty flag generation + always @ (posedge rd_clk) begin + if (rd_rst_i) begin + ram_empty_i <= 1'b1; + end else begin + ram_empty_i <= going_empty | (~leaving_empty & ram_empty_i); + end + end + + if (EN_AE == 1) begin : gae_cc_std + always @ (posedge rd_clk) begin + if (rd_rst_i) begin + ram_aempty_i <= 1'b1; + end else begin + ram_aempty_i <= going_aempty | (~leaving_aempty & ram_aempty_i); + end + end + end : gae_cc_std + + // Full flag generation + if (FULL_RST_VAL == 1) begin : gen_full_rst_val + always @ (posedge wr_clk) begin + if (wrst_busy) begin + ram_full_i <= FULL_RST_VAL; + ram_full_n <= ~FULL_RST_VAL; + end else begin + if (clr_full) begin + ram_full_i <= 1'b0; + ram_full_n <= 1'b1; + end else begin + ram_full_i <= going_full | (~leaving_full & ram_full_i); + ram_full_n <= ~(going_full | (~leaving_full & ram_full_i)); + end + end + end + end : gen_full_rst_val + else begin : ngen_full_rst_val + always @ (posedge wr_clk) begin + if (wrst_busy) begin + ram_full_i <= 1'b0; + ram_full_n <= 1'b1; + end else begin + ram_full_i <= going_full | (~leaving_full & ram_full_i); + ram_full_n <= ~(going_full | (~leaving_full & ram_full_i)); + end + end + end : ngen_full_rst_val + + if (EN_AF == 1) begin : gaf_cc + always @ (posedge wr_clk) begin + if (wrst_busy) begin + ram_afull_i <= FULL_RST_VAL; + end else if (~rst) begin + if (clr_full) begin + ram_afull_i <= 1'b0; + end else begin + ram_afull_i <= going_afull | (~leaving_afull & ram_afull_i); + end + end + end + end : gaf_cc + // Programmable Full flag generation + if ((WR_PNTR_WIDTH == RD_PNTR_WIDTH) && (RELATED_CLOCKS == 0)) begin : wrp_eq_rdp_pf_cc + if (EN_PF == 1) begin : gpf_cc_sym + + assign wr_pntr_plus1_pf = {wr_pntr_plus1,wr_pntr_plus1_pf_carry}; + assign rd_pntr_wr_adj_inv_pf = {~rd_pntr_wr_adj,rd_pntr_wr_adj_pf_carry}; + + // Delayed write/read enable for PF generation + always @ (posedge wr_clk) begin + if (wrst_busy) begin + ram_wr_en_pf_q <= 1'b0; + ram_rd_en_pf_q <= 1'b0; + end else begin + ram_wr_en_pf_q <= ram_wr_en_pf; + ram_rd_en_pf_q <= ram_rd_en_pf; + end + end + + // PF carry generation + assign wr_pntr_plus1_pf_carry = ram_wr_en_i & ~ram_rd_en_pf; + assign rd_pntr_wr_adj_pf_carry = ram_wr_en_i & ~ram_rd_en_pf; + + // PF diff pointer generation + always @ (posedge wr_clk) begin + if (wrst_busy) + diff_pntr_pf_q <= {WR_PNTR_WIDTH{1'b0}}; + else + diff_pntr_pf_q <= wr_pntr_plus1_pf + rd_pntr_wr_adj_inv_pf; + end + assign diff_pntr_pf = diff_pntr_pf_q[WR_PNTR_WIDTH:1]; + + always @ (posedge wr_clk) begin + if (wrst_busy) + prog_full_i <= FULL_RST_VAL; + else if (clr_full) + prog_full_i <= 1'b0; + else if ((diff_pntr_pf == PF_THRESH_ADJ) & ram_wr_en_pf_q & ~ram_rd_en_pf_q) + prog_full_i <= 1'b1; + else if ((diff_pntr_pf == PF_THRESH_ADJ) & ~ram_wr_en_pf_q & ram_rd_en_pf_q) + prog_full_i <= 1'b0; + else + prog_full_i <= prog_full_i; + end + end : gpf_cc_sym + + if (EN_PE == 1) begin : gpe_cc_sym + always @(posedge rd_clk) begin + if (rd_rst_i) begin + read_only_q <= 1'b0; + write_only_q <= 1'b0; + diff_pntr_pe <= 0; + end + else begin + read_only_q <= read_only; + write_only_q <= write_only; + // Add 1 to the difference pointer value when write or both write & read or no write & read happen. + if (read_only) + diff_pntr_pe <= wr_pntr_rd_adj - rd_pntr - 1; + else + diff_pntr_pe <= wr_pntr_rd_adj - rd_pntr; + end + end + + always @(posedge rd_clk) begin + if (rd_rst_i) + prog_empty_i <= 1'b1; + else begin + if (diff_pntr_pe == PE_THRESH_ADJ && read_only_q) + prog_empty_i <= 1'b1; + else if (diff_pntr_pe == PE_THRESH_ADJ && write_only_q) + prog_empty_i <= 1'b0; + else + prog_empty_i <= prog_empty_i; + end + end + end : gpe_cc_sym + end : wrp_eq_rdp_pf_cc + + if ((WR_PNTR_WIDTH != RD_PNTR_WIDTH) && (RELATED_CLOCKS == 0)) begin : wrp_neq_rdp_pf_cc + if (EN_PF == 1) begin : gpf_cc_asym + // PF diff pointer generation + always @ (posedge wr_clk) begin + if (wrst_busy) + diff_pntr_pf_q <= {WR_PNTR_WIDTH{1'b0}}; + else if (~ram_full_i) + diff_pntr_pf_q[WR_PNTR_WIDTH:1] <= wr_pntr + ~rd_pntr_wr_adj + 1; + end + assign diff_pntr_pf = diff_pntr_pf_q[WR_PNTR_WIDTH:1]; + always @ (posedge wr_clk) begin + if (wrst_busy) + prog_full_i <= FULL_RST_VAL; + else if (clr_full) + prog_full_i <= 1'b0; + else if (~ram_full_i) begin + if (diff_pntr_pf >= PF_THRESH_ADJ) + prog_full_i <= 1'b1; + else if (diff_pntr_pf < PF_THRESH_ADJ) + prog_full_i <= 1'b0; + else + prog_full_i <= prog_full_i; + end + end + end : gpf_cc_asym + if (EN_PE == 1) begin : gpe_cc_asym + // Programmanble Empty flag Generation + // Diff pointer Generation + localparam [RD_PNTR_WIDTH-1 : 0] DIFF_MAX_RD = {RD_PNTR_WIDTH{1'b1}}; + wire [RD_PNTR_WIDTH-1:0] diff_pntr_pe_max; + wire carry; + reg [RD_PNTR_WIDTH : 0] diff_pntr_pe_asym = 'b0; + wire [RD_PNTR_WIDTH : 0] wr_pntr_rd_adj_asym; + wire [RD_PNTR_WIDTH : 0] rd_pntr_asym; + reg full_reg; + reg rst_full_ff_reg1; + reg rst_full_ff_reg2; + + assign diff_pntr_pe_max = DIFF_MAX_RD; + assign wr_pntr_rd_adj_asym[RD_PNTR_WIDTH:0] = {wr_pntr_rd_adj,1'b1}; + assign rd_pntr_asym[RD_PNTR_WIDTH:0] = {~rd_pntr,1'b1}; + + always @(posedge rd_clk ) begin + if (rd_rst_i) begin + diff_pntr_pe_asym <= 0; + full_reg <= 0; + rst_full_ff_reg1 <= 1; + rst_full_ff_reg2 <= 1; + diff_pntr_pe_reg1 <= 0; + end else begin + diff_pntr_pe_asym <= wr_pntr_rd_adj_asym + rd_pntr_asym; + full_reg <= ram_full_i; + rst_full_ff_reg1 <= FULL_RST_VAL; + rst_full_ff_reg2 <= rst_full_ff_reg1; + end + end + wire [RD_PNTR_WIDTH-1:0] diff_pntr_pe_i; + assign carry = (~(|(diff_pntr_pe_asym [RD_PNTR_WIDTH : 1]))); + assign diff_pntr_pe_i = (full_reg && ~rst_d2 && carry ) ? diff_pntr_pe_max : diff_pntr_pe_asym[RD_PNTR_WIDTH:1]; + + always @(posedge rd_clk) begin + if (rd_rst_i) + prog_empty_i <= 1'b1; + else begin + if (diff_pntr_pe_i <= PE_THRESH_ADJ) + prog_empty_i <= 1'b1; + else if (diff_pntr_pe_i > PE_THRESH_ADJ) + prog_empty_i <= 1'b0; + else + prog_empty_i <= prog_empty_i; + end + end + end : gpe_cc_asym + end : wrp_neq_rdp_pf_cc + + end : gen_pntr_flags_cc + + if (READ_MODE == 0 && FIFO_READ_LATENCY > 1) begin : gen_regce_std + xpm_reg_pipe_bit #(FIFO_READ_LATENCY-1, 0) + regce_pipe_inst (rd_rst_i, rd_clk, ram_rd_en_i, ram_regce_pipe); + end : gen_regce_std + if (!(READ_MODE == 0 && FIFO_READ_LATENCY > 1)) begin : gnen_regce_std + assign ram_regce_pipe = 1'b0; + end : gnen_regce_std + + if (!((READ_MODE == 1 || READ_MODE == 2)&& FIFO_MEMORY_TYPE != 4)) begin : gn_fwft + assign invalid_state = 1'b0; + end : gn_fwft + //if (READ_MODE == 1 && FIFO_MEMORY_TYPE != 4) begin : gen_fwft + if (READ_MODE != 0 && FIFO_MEMORY_TYPE != 4) begin : gen_fwft + // First word fall through logic + + //localparam invalid = 0; + //localparam stage1_valid = 2; + //localparam stage2_valid = 1; + //localparam both_stages_valid = 3; + + //reg [1:0] curr_fwft_state = invalid; + //reg [1:0] next_fwft_state;// = invalid; + wire next_fwft_state_d1; + assign invalid_state = ~|curr_fwft_state; + assign valid_fwft = next_fwft_state_d1; + assign ram_valid_fwft = curr_fwft_state[1]; + + xpm_fifo_reg_bit #(0) + next_state_d1_inst (1'b0, rd_clk, next_fwft_state[0], next_fwft_state_d1); + //FSM : To generate the enable, clock enable for xpm_memory and to generate + //empty signal + //FSM : Next state Assignment + if (READ_MODE == 1) begin : gen_fwft_ns + always @(curr_fwft_state or ram_empty_i or rd_en) begin + case (curr_fwft_state) + invalid: begin + if (~ram_empty_i) + next_fwft_state = stage1_valid; + else + next_fwft_state = invalid; + end + stage1_valid: begin + if (ram_empty_i) + next_fwft_state = stage2_valid; + else + next_fwft_state = both_stages_valid; + end + stage2_valid: begin + if (ram_empty_i && rd_en) + next_fwft_state = invalid; + else if (~ram_empty_i && rd_en) + next_fwft_state = stage1_valid; + else if (~ram_empty_i && ~rd_en) + next_fwft_state = both_stages_valid; + else + next_fwft_state = stage2_valid; + end + both_stages_valid: begin + if (ram_empty_i && rd_en) + next_fwft_state = stage2_valid; + else if (~ram_empty_i && rd_en) + next_fwft_state = both_stages_valid; + else + next_fwft_state = both_stages_valid; + end + default: next_fwft_state = invalid; + endcase + end + end : gen_fwft_ns + if (READ_MODE == 2) begin : gen_fwft_ns_ll + always @(curr_fwft_state or ram_empty_i or rd_en) begin + case (curr_fwft_state) + invalid: begin + if (~ram_empty_i) + next_fwft_state = stage1_valid; + else + next_fwft_state = invalid; + end + stage1_valid: begin + if (ram_empty_i && rd_en) + next_fwft_state = invalid; + else + next_fwft_state = stage1_valid; + end + default: next_fwft_state = invalid; + endcase + end + end : gen_fwft_ns_ll + // FSM : current state assignment + always @ (posedge rd_clk) begin + if (rd_rst_i) + curr_fwft_state <= invalid; + else + curr_fwft_state <= next_fwft_state; + end + + reg ram_regout_en; + + // FSM(output assignments) : clock enable generation for xpm_memory + if (READ_MODE == 1) begin : gen_fwft_ro + always @(curr_fwft_state or rd_en) begin + case (curr_fwft_state) + invalid: ram_regout_en = 1'b0; + stage1_valid: ram_regout_en = 1'b1; + stage2_valid: ram_regout_en = 1'b0; + both_stages_valid: ram_regout_en = rd_en; + default: ram_regout_en = 1'b0; + endcase + end + end : gen_fwft_ro + if (READ_MODE == 2) begin : gen_fwft_ro_ll + always @(curr_fwft_state or rd_en or ram_empty_i or fe_of_empty) begin + case (curr_fwft_state) + invalid: ram_regout_en = fe_of_empty; + stage1_valid: ram_regout_en = rd_en & !ram_empty_i; + default: ram_regout_en = 1'b0; + endcase + end + end : gen_fwft_ro_ll + + // FSM(output assignments) : rd_en (enable) signal generation for xpm_memory + if (READ_MODE == 1) begin : gen_fwft_re + always @(curr_fwft_state or ram_empty_i or rd_en) begin + case (curr_fwft_state) + invalid : + if (~ram_empty_i) + rd_en_fwft = 1'b1; + else + rd_en_fwft = 1'b0; + stage1_valid : + if (~ram_empty_i) + rd_en_fwft = 1'b1; + else + rd_en_fwft = 1'b0; + stage2_valid : + if (~ram_empty_i) + rd_en_fwft = 1'b1; + else + rd_en_fwft = 1'b0; + both_stages_valid : + if (~ram_empty_i && rd_en) + rd_en_fwft = 1'b1; + else + rd_en_fwft = 1'b0; + default : + rd_en_fwft = 1'b0; + endcase + end + end : gen_fwft_re + if (READ_MODE == 2) begin : gen_fwft_re_ll + always @(curr_fwft_state or ram_empty_i or rd_en) begin + case (curr_fwft_state) + invalid : + if (~ram_empty_i) + rd_en_fwft = 1'b1; + else + rd_en_fwft = 1'b0; + stage1_valid : + if (~ram_empty_i && rd_en) + rd_en_fwft = 1'b1; + else + rd_en_fwft = 1'b0; + default : + rd_en_fwft = 1'b0; + endcase + end + end : gen_fwft_re_ll + // assingment to control regce xpm_memory + assign ram_regce = ram_regout_en; + + reg going_empty_fwft; + reg leaving_empty_fwft; + + if (READ_MODE == 1) begin : gen_fwft_ge + always @(curr_fwft_state or rd_en) begin + case (curr_fwft_state) + stage2_valid : going_empty_fwft = rd_en; + default : going_empty_fwft = 1'b0; + endcase + end + + always @(curr_fwft_state or rd_en) begin + case (curr_fwft_state) + stage1_valid : leaving_empty_fwft = 1'b1; + default : leaving_empty_fwft = 1'b0; + endcase + end + end : gen_fwft_ge + if (READ_MODE == 2) begin : gen_fwft_ge_ll + always @(curr_fwft_state or rd_en or ram_empty_i) begin + case (curr_fwft_state) + stage1_valid : going_empty_fwft = rd_en & ram_empty_i; + default : going_empty_fwft = 1'b0; + endcase + end + + always @ (posedge rd_clk) begin + if (rd_rst_i) begin + ram_empty_i_d1 <= 1'b1; + end else begin + ram_empty_i_d1 <= ram_empty_i; + end + end + assign fe_of_empty = ram_empty_i_d1 & !ram_empty_i; + + always @(curr_fwft_state or fe_of_empty) begin + case (curr_fwft_state) + invalid : leaving_empty_fwft = fe_of_empty; + stage1_valid : leaving_empty_fwft = 1'b1; + default : leaving_empty_fwft = 1'b0; + endcase + end + end : gen_fwft_ge_ll + + // fwft empty signal generation + always @ (posedge rd_clk) begin + if (rd_rst_i) begin + empty_fwft_i <= 1'b1; + empty_fwft_fb <= 1'b1; + end else begin + empty_fwft_i <= going_empty_fwft | (~ leaving_empty_fwft & empty_fwft_fb); + empty_fwft_fb <= going_empty_fwft | (~ leaving_empty_fwft & empty_fwft_fb); + end + end + + if (EN_AE == 1) begin : gae_fwft + reg going_aempty_fwft; + reg leaving_aempty_fwft; + + if (READ_MODE == 1) begin : gen_fwft_ae + always @(curr_fwft_state or rd_en or ram_empty_i) begin + case (curr_fwft_state) + both_stages_valid : going_aempty_fwft = rd_en & ram_empty_i; + default : going_aempty_fwft = 1'b0; + endcase + end + end : gen_fwft_ae + if (READ_MODE == 2) begin : gen_fwft_ae_ll + always @(curr_fwft_state or rd_en or ram_empty_i) begin + case (curr_fwft_state) + stage1_valid : going_aempty_fwft = !rd_en & ram_empty_i; + default : going_aempty_fwft = 1'b0; + endcase + end + end : gen_fwft_ae_ll + + always @(curr_fwft_state or rd_en or ram_empty_i) begin + case (curr_fwft_state) + stage1_valid : leaving_aempty_fwft = ~ram_empty_i; + stage2_valid : leaving_aempty_fwft = ~(rd_en | ram_empty_i); + default : leaving_aempty_fwft = 1'b0; + endcase + end + + always @ (posedge rd_clk) begin + if (rd_rst_i) begin + aempty_fwft_i <= 1'b1; + end else begin + aempty_fwft_i <= going_aempty_fwft | (~ leaving_aempty_fwft & aempty_fwft_i); + end + end + end : gae_fwft + + if (EN_DVLD == 1) begin : gdvld_fwft + always @ (posedge rd_clk) begin + if (rd_rst_i) begin + data_valid_fwft <= 1'b0; + end else begin + data_valid_fwft <= ~(going_empty_fwft | (~ leaving_empty_fwft & empty_fwft_fb)); + end + end + end : gdvld_fwft + + xpm_fifo_reg_bit #(0) + empty_fwft_d1_inst (1'b0, rd_clk, leaving_empty_fwft, empty_fwft_d1); + + wire ge_fwft_d1; + xpm_fifo_reg_bit #(0) + ge_fwft_d1_inst (1'b0, rd_clk, going_empty_fwft, ge_fwft_d1); + + wire count_up ; + wire count_down; + wire count_en ; + wire count_rst ; + assign count_up = (next_fwft_state == 2'b10 && ~|curr_fwft_state) | (curr_fwft_state == 2'b10 && &next_fwft_state) | (curr_fwft_state == 2'b01 && &next_fwft_state); + assign count_down = (next_fwft_state == 2'b01 && &curr_fwft_state) | (curr_fwft_state == 2'b01 && ~|next_fwft_state); + assign count_en = count_up | count_down; + assign count_rst = (rd_rst_i | (~|curr_fwft_state & ~|next_fwft_state)); + + xpm_counter_updn # (2, 0) + rdpp1_inst (count_rst, rd_clk, count_en, count_up, count_down, extra_words_fwft); + + + end : gen_fwft + + if (READ_MODE == 0) begin : ngen_fwft + assign le_fwft_re = 1'b0; + assign le_fwft_fe = 1'b0; + assign extra_words_fwft = 2'h0; + end : ngen_fwft + + // output data bus assignment + if (FG_EQ_ASYM_DOUT == 0) begin : nfg_eq_asym_dout + assign dout = dout_i; + end : nfg_eq_asym_dout + + // Overflow and Underflow flag generation + if (EN_UF == 1) begin : guf + always @ (posedge rd_clk) begin + underflow_i <= (rd_rst_i | empty_i) & rd_en; + end + assign underflow = underflow_i; + end : guf + if (EN_UF == 0) begin : gnuf + assign underflow = 1'b0; + end : gnuf + + if (EN_OF == 1) begin : gof + always @ (posedge wr_clk) begin + overflow_i <= (wrst_busy | rst_d1 | ram_full_i) & wr_en; + end + assign overflow = overflow_i; + end : gof + if (EN_OF == 0) begin : gnof + assign overflow = 1'b0; + end : gnof + + // ------------------------------------------------------------------------------------------------------------------- + // Write Data Count for Independent Clocks FIFO + // ------------------------------------------------------------------------------------------------------------------- + if (EN_WDC == 1) begin : gwdc + reg [WR_DC_WIDTH_EXT-1:0] wr_data_count_i; + wire [WR_DC_WIDTH_EXT-1:0] diff_wr_rd_pntr; + assign diff_wr_rd_pntr = wr_pntr_ext-rd_pntr_wr_adj_dc; + always @ (posedge wr_clk) begin + if (wrst_busy) + wr_data_count_i <= {WR_DC_WIDTH_EXT{1'b0}}; + else + wr_data_count_i <= diff_wr_rd_pntr; + end + assign wr_data_count = wr_data_count_i[WR_DC_WIDTH_EXT-1:WR_DC_WIDTH_EXT-WR_DATA_COUNT_WIDTH]; + end : gwdc + if (EN_WDC == 0) begin : gnwdc + assign wr_data_count = {WR_DC_WIDTH_EXT{1'b0}}; + end : gnwdc + + // ------------------------------------------------------------------------------------------------------------------- + // Read Data Count for Independent Clocks FIFO + // ------------------------------------------------------------------------------------------------------------------- + if (EN_RDC == 1) begin : grdc + reg [RD_DC_WIDTH_EXT-1:0] rd_data_count_i; + wire [RD_DC_WIDTH_EXT-1:0] diff_wr_rd_pntr_rdc; + assign diff_wr_rd_pntr_rdc = wr_pntr_rd_adj_dc-rd_pntr_ext+extra_words_fwft; + always @ (posedge rd_clk) begin + if (rd_rst_i | invalid_state) + rd_data_count_i <= {RD_DC_WIDTH_EXT{1'b0}}; + else + rd_data_count_i <= diff_wr_rd_pntr_rdc; + end + assign rd_data_count = rd_data_count_i[RD_DC_WIDTH_EXT-1:RD_DC_WIDTH_EXT-RD_DATA_COUNT_WIDTH]; + end : grdc + if (EN_RDC == 0) begin : gnrdc + assign rd_data_count = {RD_DC_WIDTH_EXT{1'b0}}; + end : gnrdc + + endgenerate + + // ------------------------------------------------------------------------------------------------------------------- + // Simulation constructs + // ------------------------------------------------------------------------------------------------------------------- + // synthesis translate_off + + `ifndef DISABLE_XPM_ASSERTIONS + initial begin + #1; + if (SIM_ASSERT_CHK == 1) + `ifdef OBSOLETE + $warning("Vivado Simulator does not currently support the SystemVerilog Assertion syntax used within XPM_FIFO. \ +Messages related to potential misuse will not be reported."); + `else + $warning("SIM_ASSERT_CHK (%0d) specifies simulation message reporting, messages related to potential misuse \ +will be reported.", SIM_ASSERT_CHK); + `endif + end + + `ifndef OBSOLETE + if (SIM_ASSERT_CHK == 1) begin : rst_usage + //Checks for valid conditions in which the src_send signal can toggle (based on src_rcv value) + //Start new handshake after previous handshake completes. + assume property (@(posedge wr_clk ) + (($past(rst) == 0) && (rst == 1)) |-> ##1 $rose(wrst_busy)) + else + $error("[%s %s-%0d] New reset (rst transitioning to 1) at %0t shouldn't occur until the previous reset \ +sequence completes (wrst_busy must be 0). This reset is ignored. Please refer to the \ +XPM_FIFO documentation in the libraries guide.", "XPM_FIFO_RESET", "S", 1, $time); + end : rst_usage + + if (SIM_ASSERT_CHK == 1 && FULL_RESET_VALUE == 1) begin : rst_full_usage + assert property (@(posedge wr_clk ) + $rose(wrst_busy) |-> ##1 $rose(full)) + else + $error("[%s %s-%0d] FULL_RESET_VALUE is set to %0d. Full flag is not 1 or transitioning to 1 at %0t.", "FULL_RESET_VALUE", "S", 2, FULL_RESET_VALUE, $time); + + assert property (@(posedge wr_clk ) + $fell(wrst_busy) |-> ##1 $fell(full)) + else + $error("[%s %s-%0d] After reset removal, full flag is not transitioning to 0 at %0t.", "FULL_CHECK", "S", 3, $time); + + end : rst_full_usage + + if (SIM_ASSERT_CHK == 1) begin : rst_empty_chk + assert property (@(posedge rd_clk ) + ($rose(rd_rst_busy) || (empty && $rose(rd_rst_busy))) |-> ##1 $rose(empty)) + else + $error("[%s %s-%0d] Reset is applied, but empty flag is not 1 or transitioning to 1 at %0t.", "EMPTY_CHECK", "S", 4, $time); + + end : rst_empty_chk + + if (SIM_ASSERT_CHK == 1) begin : sleep_chk + assert property (@(posedge wr_clk ) + ($fell(sleep) |-> !wr_en[*WAKEUP_TIME])) + else + $error("[%s %s-%0d] 'sleep' is deasserted at %0t, but wr_en must be low for %0d wr_clk cycles after %0t", "SLEEP_CHECK", "S", 6, $time, WAKEUP_TIME, $time); + + assert property (@(posedge rd_clk ) + ($fell(sleep) |-> !rd_en[*WAKEUP_TIME])) + else + $error("[%s %s-%0d] 'sleep' is deasserted at %0t, but rd_en must be low for %0d rd_clk cycles after %0t", "SLEEP_CHECK", "S", 7, $time, WAKEUP_TIME, $time); + end : sleep_chk + + if (SIM_ASSERT_CHK == 1) begin : flag_chk + + assert property (@(posedge wr_clk ) (!overflow)) else $warning("[%s %s-%0d] Overflow detected at %0t", "OVERFLOW_CHECK", "S", 8, $time); + + assert property (@(posedge rd_clk ) (!underflow)) else $warning("[%s %s-%0d] Underflow detected at %0t", "UNDERFLOW_CHECK", "S", 9, $time); + + end : flag_chk + + `endif + `endif + + // synthesis translate_on +endmodule : xpm_fifo_base + +//******************************************************************************************************************** + +module xpm_fifo_rst # ( + parameter integer COMMON_CLOCK = 1, + parameter integer CDC_DEST_SYNC_FF = 2, + parameter integer SIM_ASSERT_CHK = 0 + +) ( + input wire rst, + input wire wr_clk, + input wire rd_clk, + output wire wr_rst, + output wire rd_rst, + output wire wr_rst_busy, + output wire rd_rst_busy +); + reg [1:0] power_on_rst = 2'h3; + wire rst_i; + + // ------------------------------------------------------------------------------------------------------------------- + // Reset Logic + // ------------------------------------------------------------------------------------------------------------------- + //Keeping the power on reset to work even when the input reset(to xpm_fifo) is not applied or not using + always @ (posedge wr_clk) begin + power_on_rst <= {power_on_rst[0], 1'b0}; + end + assign rst_i = power_on_rst[1] | rst; + + // Write and read reset generation for common clock FIFO + if (COMMON_CLOCK == 1) begin : gen_rst_cc + reg [2:0] fifo_wr_rst_cc = 3'b00; + assign wr_rst = fifo_wr_rst_cc[2]; + assign rd_rst = fifo_wr_rst_cc[2]; + assign rd_rst_busy = fifo_wr_rst_cc[2]; + assign wr_rst_busy = fifo_wr_rst_cc[2]; + + // synthesis translate_off + `ifndef DISABLE_XPM_ASSERTIONS + if (SIM_ASSERT_CHK == 1) begin: assert_rst + always @ (posedge wr_clk) begin + assert (!$isunknown(rst)) else $warning ("Input port 'rst' has unknown value 'X' or 'Z' at %0t. This may cause the outputs of FIFO to be 'X' or 'Z' in simulation. Ensure 'rst' has a valid value ('0' or '1')",$time); + end + end : assert_rst + `endif + // synthesis translate_on + + always @ (posedge wr_clk) begin + if (rst_i) begin + fifo_wr_rst_cc <= 3'h7; + end else begin + fifo_wr_rst_cc <= {fifo_wr_rst_cc[1:0],1'b0}; + end + end + end : gen_rst_cc + + // Write and read reset generation for independent clock FIFO + if (COMMON_CLOCK == 0) begin : gen_rst_ic + wire fifo_wr_rst_rd; + wire fifo_rd_rst_wr_i; + reg fifo_wr_rst_i = 1'b0; + reg wr_rst_busy_i = 1'b0; + reg fifo_rd_rst_i = 1'b0; + reg fifo_rd_rst_ic = 1'b0; + reg fifo_wr_rst_ic = 1'b0; + reg wr_rst_busy_ic = 1'b0; + reg rst_seq_reentered = 1'b0; + + assign wr_rst = fifo_wr_rst_ic | wr_rst_busy_ic; + assign rd_rst = fifo_rd_rst_ic; + assign rd_rst_busy = fifo_rd_rst_ic; + assign wr_rst_busy = wr_rst_busy_ic; + + (* fsm_safe_state = "default_state" *) enum logic [2:0] {WRST_IDLE = 3'b000, + WRST_IN = 3'b010, + WRST_OUT = 3'b111, + WRST_EXIT = 3'b110, + WRST_GO2IDLE = 3'b100} curr_wrst_state = WRST_IDLE, next_wrst_state = WRST_IDLE; + + (* fsm_safe_state = "default_state" *) enum logic [1:0] {RRST_IDLE = 2'b00, + RRST_IN = 2'b10, + RRST_OUT = 2'b11, + RRST_EXIT = 2'b01} curr_rrst_state = RRST_IDLE, next_rrst_state = RRST_IDLE; + + // synthesis translate_off + `ifndef DISABLE_XPM_ASSERTIONS + if (SIM_ASSERT_CHK == 1) begin: assert_rst + always @ (posedge wr_clk) begin + assert (!$isunknown(rst)) else $warning ("Input port 'rst' has unknown value 'X' or 'Z' at %0t. This may cause the outputs of FIFO to be 'X' or 'Z' in simulation. Ensure 'rst' has a valid value ('0' or '1')",$time); + end + end : assert_rst + `endif + + // synthesis translate_on + + always @ (posedge wr_clk) begin + if (rst_i) begin + rst_seq_reentered <= 1'b0; + end else begin + if (curr_wrst_state == WRST_GO2IDLE) begin + rst_seq_reentered <= 1'b1; + end + end + end + + always @* begin + case (curr_wrst_state) + WRST_IDLE: begin + if (rst_i) + next_wrst_state <= WRST_IN; + else + next_wrst_state <= WRST_IDLE; + end + WRST_IN: begin + if (rst_i) + next_wrst_state <= WRST_IN; + else if (fifo_rd_rst_wr_i) + next_wrst_state <= WRST_OUT; + else + next_wrst_state <= WRST_IN; + end + WRST_OUT: begin + if (rst_i) + next_wrst_state <= WRST_IN; + else if (~fifo_rd_rst_wr_i) + next_wrst_state <= WRST_EXIT; + else + next_wrst_state <= WRST_OUT; + end + WRST_EXIT: begin + if (rst_i) + next_wrst_state <= WRST_IN; + else if (~rst & ~rst_seq_reentered) + next_wrst_state <= WRST_GO2IDLE; + else if (rst_seq_reentered) + next_wrst_state <= WRST_IDLE; + else + next_wrst_state <= WRST_EXIT; + end + WRST_GO2IDLE: begin + next_wrst_state <= WRST_IN; + end + default: next_wrst_state <= WRST_IDLE; + endcase + end + + always @ (posedge wr_clk) begin + curr_wrst_state <= next_wrst_state; + fifo_wr_rst_ic <= fifo_wr_rst_i; + wr_rst_busy_ic <= wr_rst_busy_i; + end + + always @* begin + case (curr_wrst_state) + WRST_IDLE : fifo_wr_rst_i = rst_i; + WRST_IN : fifo_wr_rst_i = 1'b1; + WRST_OUT : fifo_wr_rst_i = 1'b0; + WRST_EXIT : fifo_wr_rst_i = 1'b0; + WRST_GO2IDLE : fifo_wr_rst_i = 1'b1; + default: fifo_wr_rst_i = fifo_wr_rst_ic; + endcase + end + + always @* begin + case (curr_wrst_state) + WRST_IDLE: wr_rst_busy_i = rst_i; + WRST_IN : wr_rst_busy_i = 1'b1; + WRST_OUT : wr_rst_busy_i = 1'b1; + WRST_EXIT: wr_rst_busy_i = 1'b1; + default: wr_rst_busy_i = wr_rst_busy_ic; + endcase + end + + always @* begin + case (curr_rrst_state) + RRST_IDLE: begin + if (fifo_wr_rst_rd) + next_rrst_state <= RRST_IN; + else + next_rrst_state <= RRST_IDLE; + end + RRST_IN : next_rrst_state <= RRST_OUT; + RRST_OUT : begin + if (~fifo_wr_rst_rd) + next_rrst_state <= RRST_EXIT; + else + next_rrst_state <= RRST_OUT; + end + RRST_EXIT: next_rrst_state <= RRST_IDLE; + default: next_rrst_state <= RRST_IDLE; + endcase + end + + always @ (posedge rd_clk) begin + curr_rrst_state <= next_rrst_state; + fifo_rd_rst_ic <= fifo_rd_rst_i; + end + + always @* begin + case (curr_rrst_state) + RRST_IDLE: fifo_rd_rst_i <= fifo_wr_rst_rd; + RRST_IN : fifo_rd_rst_i <= 1'b1; + RRST_OUT : fifo_rd_rst_i <= 1'b1; + RRST_EXIT: fifo_rd_rst_i <= 1'b0; + default: fifo_rd_rst_i <= 1'b0; + endcase + end + + // Synchronize the wr_rst (fifo_wr_rst_ic) in read clock domain + xpm_cdc_sync_rst #( + .DEST_SYNC_FF (CDC_DEST_SYNC_FF), + .INIT (0), + .INIT_SYNC_FF (1), + .SIM_ASSERT_CHK (0), + .VERSION (0)) + wrst_rd_inst ( + .src_rst (fifo_wr_rst_ic), + .dest_clk (rd_clk), + .dest_rst (fifo_wr_rst_rd)); + + // Synchronize the rd_rst (fifo_rd_rst_ic) in write clock domain + xpm_cdc_sync_rst #( + .DEST_SYNC_FF (CDC_DEST_SYNC_FF), + .INIT (0), + .INIT_SYNC_FF (1), + .SIM_ASSERT_CHK (0), + .VERSION (0)) + rrst_wr_inst ( + .src_rst (fifo_rd_rst_ic), + .dest_clk (wr_clk), + .dest_rst (fifo_rd_rst_wr_i)); + end : gen_rst_ic +endmodule : xpm_fifo_rst + + +//******************************************************************************************************************** + +//******************************************************************************************************************** +// ------------------------------------------------------------------------------------------------------------------- +// Up-Down Counter +// ------------------------------------------------------------------------------------------------------------------- +//******************************************************************************************************************** + +module xpm_counter_updn # ( + parameter integer COUNTER_WIDTH = 4, + parameter integer RESET_VALUE = 0 + +) ( + input wire rst, + input wire clk, + input wire cnt_en, + input wire cnt_up, + input wire cnt_down, + output wire [COUNTER_WIDTH-1:0] count_value +); + reg [COUNTER_WIDTH-1:0] count_value_i = RESET_VALUE; + assign count_value = count_value_i; + always @ (posedge clk) begin + if (rst) begin + count_value_i <= RESET_VALUE; + end else if (cnt_en) begin + count_value_i <= count_value_i + cnt_up - cnt_down; + end + end +endmodule : xpm_counter_updn + +//******************************************************************************************************************** +//******************************************************************************************************************** + +module xpm_fifo_reg_vec # ( + parameter integer REG_WIDTH = 4 + +) ( + input wire rst, + input wire clk, + input wire [REG_WIDTH-1:0] reg_in, + output wire [REG_WIDTH-1:0] reg_out +); + reg [REG_WIDTH-1:0] reg_out_i = {REG_WIDTH{1'b0}}; + always @ (posedge clk) begin + if (rst) + reg_out_i <= {REG_WIDTH{1'b0}}; + else + reg_out_i <= reg_in; + end + assign reg_out = reg_out_i; +endmodule : xpm_fifo_reg_vec + +//******************************************************************************************************************** +//******************************************************************************************************************** + +module xpm_fifo_reg_bit # ( + parameter integer RST_VALUE = 0 + +) ( + input wire rst, + input wire clk, + input wire d_in, + output reg d_out = RST_VALUE +); + always @ (posedge clk) begin + if (rst) + d_out <= RST_VALUE; + else + d_out <= d_in; + end +endmodule : xpm_fifo_reg_bit +//******************************************************************************************************************** +//******************************************************************************************************************** + +module xpm_reg_pipe_bit # ( + parameter integer PIPE_STAGES = 1, + parameter integer RST_VALUE = 0 + +) ( + input wire rst, + input wire clk, + input wire pipe_in, + output wire pipe_out +); + wire pipe_stage_ff [PIPE_STAGES:0]; + + assign pipe_stage_ff[0] = pipe_in; + + for (genvar pipestage = 0; pipestage < PIPE_STAGES ;pipestage = pipestage + 1) begin : gen_pipe_bit + xpm_fifo_reg_bit #(RST_VALUE) + pipe_bit_inst (rst, clk, pipe_stage_ff[pipestage], pipe_stage_ff[pipestage+1]); + end : gen_pipe_bit + + assign pipe_out = pipe_stage_ff[PIPE_STAGES]; +endmodule : xpm_reg_pipe_bit +//******************************************************************************************************************** +//******************************************************************************************************************** + + +(* XPM_MODULE = "TRUE", KEEP_HIERARCHY = "SOFT" *) +module xpm_fifo_sync # ( + + // Common module parameters + parameter FIFO_MEMORY_TYPE = "auto", + parameter ECC_MODE = "no_ecc", + parameter integer SIM_ASSERT_CHK = 0, + parameter integer CASCADE_HEIGHT = 0, + + parameter integer FIFO_WRITE_DEPTH = 2048, + parameter integer WRITE_DATA_WIDTH = 32, + parameter integer WR_DATA_COUNT_WIDTH = 1, + parameter integer PROG_FULL_THRESH = 10, + parameter integer FULL_RESET_VALUE = 0, + parameter USE_ADV_FEATURES = "0707", + + parameter READ_MODE = "std", + parameter integer FIFO_READ_LATENCY = 1, + parameter integer READ_DATA_WIDTH = WRITE_DATA_WIDTH, + parameter integer RD_DATA_COUNT_WIDTH = 1, + parameter integer PROG_EMPTY_THRESH = 10, + parameter DOUT_RESET_VALUE = "0", + + parameter WAKEUP_TIME = 0 + +) ( + + // Common module ports + input wire sleep, + input wire rst, + + // Write Domain ports + input wire wr_clk, + input wire wr_en, + input wire [WRITE_DATA_WIDTH-1:0] din, + output wire full, + output wire prog_full, + output wire [WR_DATA_COUNT_WIDTH-1:0] wr_data_count, + output wire overflow, + output wire wr_rst_busy, + output wire almost_full, + output wire wr_ack, + + // Read Domain ports + input wire rd_en, + output wire [READ_DATA_WIDTH-1:0] dout, + output wire empty, + output wire prog_empty, + output wire [RD_DATA_COUNT_WIDTH-1:0] rd_data_count, + output wire underflow, + output wire rd_rst_busy, + output wire almost_empty, + output wire data_valid, + + // ECC Related ports + input wire injectsbiterr, + input wire injectdbiterr, + output wire sbiterr, + output wire dbiterr +); + // Function to convert ASCII value to binary + function [3:0] str2bin; + input [7:0] str_val_ascii; + if((str_val_ascii == 8'h30) || (str_val_ascii == 8'h31) || + (str_val_ascii == 8'h32) || (str_val_ascii == 8'h33) || + (str_val_ascii == 8'h34) || (str_val_ascii == 8'h35) || + (str_val_ascii == 8'h36) || (str_val_ascii == 8'h37) || + (str_val_ascii == 8'h38) || (str_val_ascii == 8'h39) || + (str_val_ascii == 8'h41) || (str_val_ascii == 8'h42) || + (str_val_ascii == 8'h43) || (str_val_ascii == 8'h44) || + (str_val_ascii == 8'h45) || (str_val_ascii == 8'h46) || + (str_val_ascii == 8'h61) || (str_val_ascii == 8'h62) || + (str_val_ascii == 8'h63) || (str_val_ascii == 8'h64) || + (str_val_ascii == 8'h65) || (str_val_ascii == 8'h66) || + (str_val_ascii == 8'h00)) begin + if (!str_val_ascii[6]) + str2bin = str_val_ascii[3:0]; + else begin + str2bin [3] = 1'b1; + str2bin [2] = str_val_ascii[2] | (str_val_ascii[1] & str_val_ascii[0]); + str2bin [1] = str_val_ascii[0] ^ str_val_ascii[1]; + str2bin [0] = !str_val_ascii[0]; + end + end + else + $error("Found Invalid character while parsing the string, please cross check the value specified for either READ_RESET_VALUE_A|B or MEMORY_INIT_PARAM (if initialization of memory through parameter is used). XPM_MEMORY supports strings (hex) that contains characters 0-9, A-F and a-f."); + endfunction + // Function that parses the complete reset value string + function logic [15:0] hstr2bin; + input [16*8-1 : 0] hstr_val; + integer rst_loop_a; + localparam integer rsta_loop_iter = 16; + logic [rsta_loop_iter-1 : 0] rst_val_conv_a_i; + for (rst_loop_a=1; rst_loop_a <= rsta_loop_iter/4; rst_loop_a = rst_loop_a+1) begin + rst_val_conv_a_i[(rst_loop_a*4)-1 -: 4] = str2bin(hstr_val[(rst_loop_a*8)-1 -: 8]); + end + return rst_val_conv_a_i[15:0]; + endfunction + + localparam [15:0] EN_ADV_FEATURE_SYNC = hstr2bin(USE_ADV_FEATURES); + + // Define local parameters for mapping with base file + localparam integer P_FIFO_MEMORY_TYPE = ( (FIFO_MEMORY_TYPE == "lutram" || FIFO_MEMORY_TYPE == "LUTRAM" || FIFO_MEMORY_TYPE == "distributed" || FIFO_MEMORY_TYPE == "DISTRIBUTED" ) ? 1 : + ( (FIFO_MEMORY_TYPE == "bram" || FIFO_MEMORY_TYPE == "BRAM" || FIFO_MEMORY_TYPE == "block" || FIFO_MEMORY_TYPE == "BLOCK") ? 2 : + ( (FIFO_MEMORY_TYPE == "uram" || FIFO_MEMORY_TYPE == "URAM" || FIFO_MEMORY_TYPE == "ultra" || FIFO_MEMORY_TYPE == "ULTRA") ? 3 : + ( (FIFO_MEMORY_TYPE == "builtin" || FIFO_MEMORY_TYPE == "BUILTIN" ) ? 4 : 0)))); + + localparam integer P_COMMON_CLOCK = 1; + + localparam integer P_ECC_MODE = ( (ECC_MODE == "no_ecc" || ECC_MODE == "NO_ECC" ) ? 0 : 1); + + localparam integer P_READ_MODE = ( (READ_MODE == "std" || READ_MODE == "STD" ) ? 0 : + ( (READ_MODE == "fwft" || READ_MODE == "FWFT") ? 1 : + ( (READ_MODE == "low_latency_fwft" || READ_MODE == "Low_Latency_FWFT") ? 2 : 3))); + + + localparam integer P_WAKEUP_TIME = ( (WAKEUP_TIME == "disable_sleep" || WAKEUP_TIME == "DISABLE_SLEEP" ) ? 0 : 2); + + initial begin : config_drc_sync + reg drc_err_flag_sync; + drc_err_flag_sync = 0; + #1; + if (EN_ADV_FEATURE_SYNC[13] != 1'b0) begin + $error("[%s %0d-%0d] USE_ADV_FEATURES[13] = %0b. This is a reserved field and must be set to 0. %m", "XPM_FIFO_SYNC", 1, 1, EN_ADV_FEATURE_SYNC[13]); + drc_err_flag_sync = 1; + end + + if (drc_err_flag_sync == 1) + #1 $finish; + end : config_drc_sync + + // ------------------------------------------------------------------------------------------------------------------- + // Generate the instantiation of the appropriate XPM module + // ------------------------------------------------------------------------------------------------------------------- + assign rd_rst_busy = wr_rst_busy; + xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE ), + .ECC_MODE (P_ECC_MODE ), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_WRITE_DEPTH ), + .WRITE_DATA_WIDTH (WRITE_DATA_WIDTH ), + .WR_DATA_COUNT_WIDTH (WR_DATA_COUNT_WIDTH ), + .PROG_FULL_THRESH (PROG_FULL_THRESH ), + .FULL_RESET_VALUE (FULL_RESET_VALUE ), + .USE_ADV_FEATURES (USE_ADV_FEATURES ), + .READ_MODE (P_READ_MODE ), + .FIFO_READ_LATENCY (FIFO_READ_LATENCY ), + .READ_DATA_WIDTH (READ_DATA_WIDTH ), + .RD_DATA_COUNT_WIDTH (RD_DATA_COUNT_WIDTH ), + .PROG_EMPTY_THRESH (PROG_EMPTY_THRESH ), + .DOUT_RESET_VALUE (DOUT_RESET_VALUE ), + .CDC_DEST_SYNC_FF (2 ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (WAKEUP_TIME ), + .VERSION (0 ) + + ) xpm_fifo_base_inst ( + .sleep (sleep), + .rst (rst), + .wr_clk (wr_clk), + .wr_en (wr_en), + .din (din), + .full (full), + .full_n (), + .prog_full (prog_full), + .wr_data_count (wr_data_count), + .overflow (overflow), + .wr_rst_busy (wr_rst_busy), + .almost_full (almost_full), + .wr_ack (wr_ack), + .rd_clk (wr_clk), + .rd_en (rd_en), + .dout (dout), + .empty (empty), + .prog_empty (prog_empty), + .rd_data_count (rd_data_count), + .underflow (underflow), + .rd_rst_busy (), + .almost_empty (almost_empty), + .data_valid (data_valid), + .injectsbiterr (injectsbiterr), + .injectdbiterr (injectdbiterr), + .sbiterr (sbiterr), + .dbiterr (dbiterr) + ); + +endmodule : xpm_fifo_sync + +//******************************************************************************************************************** +//******************************************************************************************************************** +//******************************************************************************************************************** + + +(* XPM_MODULE = "TRUE", DONT_TOUCH = "TRUE" *) +module xpm_fifo_async # ( + + // Common module parameters + parameter FIFO_MEMORY_TYPE = "auto", + parameter ECC_MODE = "no_ecc", + parameter integer RELATED_CLOCKS = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer CASCADE_HEIGHT = 0, + + parameter integer FIFO_WRITE_DEPTH = 2048, + parameter integer WRITE_DATA_WIDTH = 32, + parameter integer WR_DATA_COUNT_WIDTH = 1, + parameter integer PROG_FULL_THRESH = 10, + parameter integer FULL_RESET_VALUE = 0, + parameter USE_ADV_FEATURES = "0707", + + parameter READ_MODE = "std", + parameter integer FIFO_READ_LATENCY = 1, + parameter integer READ_DATA_WIDTH = WRITE_DATA_WIDTH, + parameter integer RD_DATA_COUNT_WIDTH = 1, + parameter integer PROG_EMPTY_THRESH = 10, + parameter DOUT_RESET_VALUE = "0", + parameter integer CDC_SYNC_STAGES = 2, + + parameter WAKEUP_TIME = 0 +) ( + + // Common module ports + input wire sleep, + input wire rst, + + // Write Domain ports + input wire wr_clk, + input wire wr_en, + input wire [WRITE_DATA_WIDTH-1:0] din, + output wire full, + output wire prog_full, + output wire [WR_DATA_COUNT_WIDTH-1:0] wr_data_count, + output wire overflow, + output wire wr_rst_busy, + output wire almost_full, + output wire wr_ack, + + // Read Domain ports + input wire rd_clk, + input wire rd_en, + output wire [READ_DATA_WIDTH-1:0] dout, + output wire empty, + output wire prog_empty, + output wire [RD_DATA_COUNT_WIDTH-1:0] rd_data_count, + output wire underflow, + output wire rd_rst_busy, + output wire almost_empty, + output wire data_valid, + + // ECC Related ports + input wire injectsbiterr, + input wire injectdbiterr, + output wire sbiterr, + output wire dbiterr +); + // Function to convert ASCII value to binary + function [3:0] str2bin; + input [7:0] str_val_ascii; + if((str_val_ascii == 8'h30) || (str_val_ascii == 8'h31) || + (str_val_ascii == 8'h32) || (str_val_ascii == 8'h33) || + (str_val_ascii == 8'h34) || (str_val_ascii == 8'h35) || + (str_val_ascii == 8'h36) || (str_val_ascii == 8'h37) || + (str_val_ascii == 8'h38) || (str_val_ascii == 8'h39) || + (str_val_ascii == 8'h41) || (str_val_ascii == 8'h42) || + (str_val_ascii == 8'h43) || (str_val_ascii == 8'h44) || + (str_val_ascii == 8'h45) || (str_val_ascii == 8'h46) || + (str_val_ascii == 8'h61) || (str_val_ascii == 8'h62) || + (str_val_ascii == 8'h63) || (str_val_ascii == 8'h64) || + (str_val_ascii == 8'h65) || (str_val_ascii == 8'h66) || + (str_val_ascii == 8'h00)) begin + if (!str_val_ascii[6]) + str2bin = str_val_ascii[3:0]; + else begin + str2bin [3] = 1'b1; + str2bin [2] = str_val_ascii[2] | (str_val_ascii[1] & str_val_ascii[0]); + str2bin [1] = str_val_ascii[0] ^ str_val_ascii[1]; + str2bin [0] = !str_val_ascii[0]; + end + end + else + $error("Found Invalid character while parsing the string, please cross check the value specified for either READ_RESET_VALUE_A|B or MEMORY_INIT_PARAM (if initialization of memory through parameter is used). XPM_MEMORY supports strings (hex) that contains characters 0-9, A-F and a-f."); + endfunction + // Function that parses the complete reset value string + function logic [15:0] hstr2bin; + input [16*8-1 : 0] hstr_val; + integer rst_loop_a; + localparam integer rsta_loop_iter = 16; + logic [rsta_loop_iter-1 : 0] rst_val_conv_a_i; + for (rst_loop_a=1; rst_loop_a <= rsta_loop_iter/4; rst_loop_a = rst_loop_a+1) begin + rst_val_conv_a_i[(rst_loop_a*4)-1 -: 4] = str2bin(hstr_val[(rst_loop_a*8)-1 -: 8]); + end + return rst_val_conv_a_i[15:0]; + endfunction + + localparam [15:0] EN_ADV_FEATURE_ASYNC = hstr2bin(USE_ADV_FEATURES); + + // Define local parameters for mapping with base file + localparam integer P_FIFO_MEMORY_TYPE = ( (FIFO_MEMORY_TYPE == "lutram" || FIFO_MEMORY_TYPE == "LUTRAM" || FIFO_MEMORY_TYPE == "distributed" || FIFO_MEMORY_TYPE == "DISTRIBUTED" ) ? 1 : + ( (FIFO_MEMORY_TYPE == "bram" || FIFO_MEMORY_TYPE == "BRAM" || FIFO_MEMORY_TYPE == "block" || FIFO_MEMORY_TYPE == "BLOCK") ? 2 : + ( (FIFO_MEMORY_TYPE == "uram" || FIFO_MEMORY_TYPE == "URAM" || FIFO_MEMORY_TYPE == "ultra" || FIFO_MEMORY_TYPE == "ULTRA") ? 3 : + ( (FIFO_MEMORY_TYPE == "builtin" || FIFO_MEMORY_TYPE == "BUILTIN" ) ? 4 : 0)))); + + localparam integer P_COMMON_CLOCK = 0; + + localparam integer P_ECC_MODE = ( (ECC_MODE == "no_ecc" || ECC_MODE == "NO_ECC" ) ? 0 : 1); + + localparam integer P_READ_MODE = ( (READ_MODE == "std" || READ_MODE == "STD" ) ? 0 : + ( (READ_MODE == "fwft" || READ_MODE == "FWFT") ? 1 : + ( (READ_MODE == "low_latency_fwft" || READ_MODE == "Low_Latency_FWFT") ? 2 : 3))); + + localparam integer P_WAKEUP_TIME = ( (WAKEUP_TIME == "disable_sleep" || WAKEUP_TIME == "DISABLE_SLEEP" ) ? 0 : 2); + + initial begin : config_drc_async + reg drc_err_flag_async; + drc_err_flag_async = 0; + #1; + if (EN_ADV_FEATURE_ASYNC[13] != 1'b0) begin + $error("[%s %0d-%0d] USE_ADV_FEATURES[13] = %0b. This is a reserved field and must be set to 0. %m", "XPM_FIFO_ASYNC", 1, 1, EN_ADV_FEATURE_ASYNC[13]); + drc_err_flag_async = 1; + end + + if (drc_err_flag_async == 1) + #1 $finish; + end : config_drc_async + + // ------------------------------------------------------------------------------------------------------------------- + // Generate the instantiation of the appropriate XPM module + // ------------------------------------------------------------------------------------------------------------------- + generate if (P_FIFO_MEMORY_TYPE != 3) begin : gnuram_async_fifo + xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (RELATED_CLOCKS ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE ), + .ECC_MODE (P_ECC_MODE ), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_WRITE_DEPTH ), + .WRITE_DATA_WIDTH (WRITE_DATA_WIDTH ), + .WR_DATA_COUNT_WIDTH (WR_DATA_COUNT_WIDTH ), + .PROG_FULL_THRESH (PROG_FULL_THRESH ), + .FULL_RESET_VALUE (FULL_RESET_VALUE ), + .USE_ADV_FEATURES (USE_ADV_FEATURES ), + .READ_MODE (P_READ_MODE ), + .FIFO_READ_LATENCY (FIFO_READ_LATENCY ), + .READ_DATA_WIDTH (READ_DATA_WIDTH ), + .RD_DATA_COUNT_WIDTH (RD_DATA_COUNT_WIDTH ), + .PROG_EMPTY_THRESH (PROG_EMPTY_THRESH ), + .DOUT_RESET_VALUE (DOUT_RESET_VALUE ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (WAKEUP_TIME ), + .VERSION (0 ) + + ) xpm_fifo_base_inst ( + .sleep (sleep), + .rst (rst), + .wr_clk (wr_clk), + .wr_en (wr_en), + .din (din), + .full (full), + .full_n (), + .prog_full (prog_full), + .wr_data_count (wr_data_count), + .overflow (overflow), + .wr_rst_busy (wr_rst_busy), + .almost_full (almost_full), + .wr_ack (wr_ack), + .rd_clk (rd_clk), + .rd_en (rd_en), + .dout (dout), + .empty (empty), + .prog_empty (prog_empty), + .rd_data_count (rd_data_count), + .underflow (underflow), + .rd_rst_busy (rd_rst_busy), + .almost_empty (almost_empty), + .data_valid (data_valid), + .injectsbiterr (injectsbiterr), + .injectdbiterr (injectdbiterr), + .sbiterr (sbiterr), + .dbiterr (dbiterr) + ); + end endgenerate // gnuram_async_fifo +endmodule : xpm_fifo_async + +//******************************************************************************************************************** +//******************************************************************************************************************** +//******************************************************************************************************************** + + +(* XPM_MODULE = "TRUE", DONT_TOUCH = "TRUE" *) +module xpm_fifo_axis # ( + + // Common module parameters + parameter CLOCKING_MODE = "common_clock", + parameter FIFO_MEMORY_TYPE = "auto", + parameter PACKET_FIFO = "false", + parameter integer FIFO_DEPTH = 2048, + parameter integer TDATA_WIDTH = 32, + parameter integer TID_WIDTH = 1, + parameter integer TDEST_WIDTH = 1, + parameter integer TUSER_WIDTH = 1, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer CASCADE_HEIGHT = 0, + + parameter ECC_MODE = "no_ecc", + parameter integer RELATED_CLOCKS = 0, + parameter USE_ADV_FEATURES = "1000", + parameter integer WR_DATA_COUNT_WIDTH = 1, + parameter integer RD_DATA_COUNT_WIDTH = 1, + parameter integer PROG_FULL_THRESH = 10, + parameter integer PROG_EMPTY_THRESH = 10, + parameter integer CDC_SYNC_STAGES = 2 + + +) ( + + // Common module ports + input wire s_aresetn, + input wire s_aclk, + input wire m_aclk, + + // AXI Streaming Slave Signals (Write side) + input wire s_axis_tvalid, + output wire s_axis_tready, + input wire [TDATA_WIDTH-1:0] s_axis_tdata, + input wire [TDATA_WIDTH/8-1:0] s_axis_tstrb, + input wire [TDATA_WIDTH/8-1:0] s_axis_tkeep, + input wire s_axis_tlast, + input wire [TID_WIDTH-1:0] s_axis_tid, + input wire [TDEST_WIDTH-1:0] s_axis_tdest, + input wire [TUSER_WIDTH-1:0] s_axis_tuser, + + // AXI Streaming Master Signals (Read side) + output wire m_axis_tvalid, + input wire m_axis_tready, + output wire [TDATA_WIDTH-1:0] m_axis_tdata, + output wire [TDATA_WIDTH/8-1:0] m_axis_tstrb, + output wire [TDATA_WIDTH/8-1:0] m_axis_tkeep, + output wire m_axis_tlast, + output wire [TID_WIDTH-1:0] m_axis_tid, + output wire [TDEST_WIDTH-1:0] m_axis_tdest, + output wire [TUSER_WIDTH-1:0] m_axis_tuser, + + // AXI Streaming Sideband Signals + output wire prog_full_axis, + output wire [WR_DATA_COUNT_WIDTH-1:0] wr_data_count_axis, + output wire almost_full_axis, + output wire prog_empty_axis, + output wire [RD_DATA_COUNT_WIDTH-1:0] rd_data_count_axis, + output wire almost_empty_axis, + + // ECC Related ports + input wire injectsbiterr_axis, + input wire injectdbiterr_axis, + output wire sbiterr_axis, + output wire dbiterr_axis +); + + function integer clog2; + input integer value; + begin + value = value-1; + for (clog2=0; value>0; clog2=clog2+1) + value = value>>1; + end + endfunction + // Function to convert ASCII value to binary + function [3:0] str2bin; + input [7:0] str_val_ascii; + if((str_val_ascii == 8'h30) || (str_val_ascii == 8'h31) || + (str_val_ascii == 8'h32) || (str_val_ascii == 8'h33) || + (str_val_ascii == 8'h34) || (str_val_ascii == 8'h35) || + (str_val_ascii == 8'h36) || (str_val_ascii == 8'h37) || + (str_val_ascii == 8'h38) || (str_val_ascii == 8'h39) || + (str_val_ascii == 8'h41) || (str_val_ascii == 8'h42) || + (str_val_ascii == 8'h43) || (str_val_ascii == 8'h44) || + (str_val_ascii == 8'h45) || (str_val_ascii == 8'h46) || + (str_val_ascii == 8'h61) || (str_val_ascii == 8'h62) || + (str_val_ascii == 8'h63) || (str_val_ascii == 8'h64) || + (str_val_ascii == 8'h65) || (str_val_ascii == 8'h66) || + (str_val_ascii == 8'h00)) begin + if (!str_val_ascii[6]) + str2bin = str_val_ascii[3:0]; + else begin + str2bin [3] = 1'b1; + str2bin [2] = str_val_ascii[2] | (str_val_ascii[1] & str_val_ascii[0]); + str2bin [1] = str_val_ascii[0] ^ str_val_ascii[1]; + str2bin [0] = !str_val_ascii[0]; + end + end + else + $error("Found Invalid character while parsing the string, please cross check the value specified for either READ_RESET_VALUE_A|B or MEMORY_INIT_PARAM (if initialization of memory through parameter is used). XPM_MEMORY supports strings (hex) that contains characters 0-9, A-F and a-f."); + endfunction + // Function that parses the complete reset value string + function logic [15:0] hstr2bin; + input [16*8-1 : 0] hstr_val; + integer rst_loop_a; + localparam integer rsta_loop_iter = 16; + logic [rsta_loop_iter-1 : 0] rst_val_conv_a_i; + for (rst_loop_a=1; rst_loop_a <= rsta_loop_iter/4; rst_loop_a = rst_loop_a+1) begin + rst_val_conv_a_i[(rst_loop_a*4)-1 -: 4] = str2bin(hstr_val[(rst_loop_a*8)-1 -: 8]); + end + return rst_val_conv_a_i[15:0]; + endfunction + +//Function to convert binary to ASCII value + function [7:0] bin2str; + input [3:0] bin_val; + if( bin_val > 4'h9) begin + bin2str [7:4] = 4'h4; + bin2str [3] = 1'b0; + bin2str [2:0] = bin_val[2:0]-1'b1; + end + else begin + bin2str [7:4] = 4'h3; + bin2str [3:0] = bin_val; + end + endfunction + + // Function that parses the complete binary value to string + function [31:0] bin2hstr; + input [15 : 0] bin_val; + integer str_pos; + localparam integer str_max_bits = 32; + for (str_pos=1; str_pos <= str_max_bits/8; str_pos = str_pos+1) begin + bin2hstr[(str_pos*8)-1 -: 8] = bin2str(bin_val[(str_pos*4)-1 -: 4]); + end + endfunction + + + localparam [15:0] EN_ADV_FEATURE_AXIS = hstr2bin(USE_ADV_FEATURES); + localparam EN_ALMOST_FULL_INT = (PACKET_FIFO == "true") ? 1'b1 : EN_ADV_FEATURE_AXIS[3]; + localparam EN_ALMOST_EMPTY_INT = (PACKET_FIFO == "true") ? 1'b1 : EN_ADV_FEATURE_AXIS[11]; + localparam EN_DATA_VALID_INT = 1'b1; + localparam [15:0] EN_ADV_FEATURE_AXIS_INT = {EN_ADV_FEATURE_AXIS[15:13], EN_DATA_VALID_INT, EN_ALMOST_EMPTY_INT, EN_ADV_FEATURE_AXIS[10:4], EN_ALMOST_FULL_INT, EN_ADV_FEATURE_AXIS[2:0]}; + localparam USE_ADV_FEATURES_INT = bin2hstr(EN_ADV_FEATURE_AXIS_INT); + + + localparam PKT_SIZE_LT8 = EN_ADV_FEATURE_AXIS[13]; + + localparam LOG_DEPTH_AXIS = clog2(FIFO_DEPTH); + localparam TDATA_OFFSET = TDATA_WIDTH; + localparam TSTRB_OFFSET = TDATA_OFFSET+(TDATA_WIDTH/8); + localparam TKEEP_OFFSET = TSTRB_OFFSET+(TDATA_WIDTH/8); + localparam TID_OFFSET = TID_WIDTH > 0 ? TKEEP_OFFSET+TID_WIDTH : TKEEP_OFFSET; + localparam TDEST_OFFSET = TDEST_WIDTH > 0 ? TID_OFFSET+TDEST_WIDTH : TID_OFFSET; + localparam TUSER_OFFSET = TUSER_WIDTH > 0 ? TDEST_OFFSET+TUSER_WIDTH : TDEST_OFFSET; + localparam AXIS_DATA_WIDTH = TUSER_OFFSET+1; + + // Define local parameters for mapping with base file + + localparam integer P_COMMON_CLOCK = ( (CLOCKING_MODE == "common_clock" || CLOCKING_MODE == "COMMON_CLOCK" || CLOCKING_MODE == "COMMON" || CLOCKING_MODE == "common") ? 1 : + ( (CLOCKING_MODE == "independent_clock" || CLOCKING_MODE == "INDEPENDENT_CLOCK" || CLOCKING_MODE == "INDEPENDENT" || CLOCKING_MODE == "independent") ? 0 : 1)); + localparam integer P_FIFO_MEMORY_TYPE = ( (FIFO_MEMORY_TYPE == "lutram" || FIFO_MEMORY_TYPE == "LUTRAM" || FIFO_MEMORY_TYPE == "distributed" || FIFO_MEMORY_TYPE == "DISTRIBUTED" ) ? 1 : + ( (FIFO_MEMORY_TYPE == "bram" || FIFO_MEMORY_TYPE == "BRAM" || FIFO_MEMORY_TYPE == "block" || FIFO_MEMORY_TYPE == "BLOCK") ? 2 : + ( (FIFO_MEMORY_TYPE == "uram" || FIFO_MEMORY_TYPE == "URAM" || FIFO_MEMORY_TYPE == "ultra" || FIFO_MEMORY_TYPE == "ULTRA") ? 3 : 0))); + + localparam integer P_ECC_MODE = ( (ECC_MODE == "no_ecc" || ECC_MODE == "NO_ECC" ) ? 0 : 1); + localparam integer P_PKT_MODE = PACKET_FIFO == "true" ? 1 : 0; + localparam AXIS_FINAL_DATA_WIDTH = P_ECC_MODE == 0 ? AXIS_DATA_WIDTH : (((AXIS_DATA_WIDTH/64)*64) + ((AXIS_DATA_WIDTH%64 == 0) ? 0 : 64)); + localparam TUSER_MAX_WIDTH = 4096 - (TDEST_OFFSET+1); + + wire rst_axis; + wire data_valid_axis; + wire rd_rst_busy_axis; + wire [AXIS_FINAL_DATA_WIDTH-1:0] axis_din; + wire [AXIS_FINAL_DATA_WIDTH-1:0] axis_dout; + + initial begin : config_drc_axis + reg drc_err_flag_axis; + drc_err_flag_axis = 0; + #1; + + if (AXIS_FINAL_DATA_WIDTH > 4096) begin + $error("[%s %0d-%0d] Total width (sum of TDATA, TID, TDEST, TKEEP, TSTRB, TUSER and TLAST) of AXI Stream FIFO (%0d) exceeds the maximum supported width (%0d). Please reduce the width of TDATA or TID or TDEST or TUSER %m", "XPM_FIFO_AXIS", 20, 2, AXIS_FINAL_DATA_WIDTH, 4096); + drc_err_flag_axis = 1; + end + + if ((TDATA_WIDTH%8 != 0) || TDATA_WIDTH < 8 || TDATA_WIDTH > 2048) begin + $error("[%s %0d-%0d] TDATA_WIDTH (%0d) value is outside of legal range. TDATA_WIDTH value must be between %0d and %0d, and it must be multiples of 8. %m", "XPM_FIFO_AXIS", 20, 3, TDATA_WIDTH, 8, 2048); + drc_err_flag_axis = 1; + end + + if (TID_WIDTH < 1 || TID_WIDTH > 32) begin + $error("[%s %0d-%0d] TID_WIDTH (%0d) value is outside of legal range. TID_WIDTH value must be between %0d and %0d, and it must be multiples of 8. %m", "XPM_FIFO_AXIS", 20, 4, TID_WIDTH, 1, 32); + drc_err_flag_axis = 1; + end + + if (TDEST_WIDTH < 1 || TDEST_WIDTH > 32) begin + $error("[%s %0d-%0d] TDEST_WIDTH (%0d) value is outside of legal range. TDEST_WIDTH value must be between %0d and %0d, and it must be multiples of 8. %m", "XPM_FIFO_AXIS", 20, 5, TDEST_WIDTH, 1, 32); + drc_err_flag_axis = 1; + end + + if (TUSER_WIDTH < 1 || TUSER_WIDTH > TUSER_MAX_WIDTH) begin + $error("[%s %0d-%0d] TUSER_WIDTH (%0d) value is outside of legal range. TUSER_WIDTH value must be between %0d and %0d, and it must be multiples of 8. %m", "XPM_FIFO_AXIS", 20, 6, TUSER_WIDTH, 1, TUSER_MAX_WIDTH); + drc_err_flag_axis = 1; + end + + if (RELATED_CLOCKS == 1 && P_PKT_MODE != 1'b0) begin + $error("[%s %0d-%0d] RELATED_CLOCKS (%0d) value is outside of legal range. RELATED_CLOCKS value must be 0 when PACKET_FIFO is set to %s. %m", "XPM_FIFO_AXIS", 20, 7, RELATED_CLOCKS, RELATED_CLOCKS); + drc_err_flag_axis = 1; + end + + if (EN_ADV_FEATURE_AXIS[13] == 1'b1 && (P_PKT_MODE != 1'b1 || P_COMMON_CLOCK != 1'b0)) begin + $error("[%s %0d-%0d] USE_ADV_FEATURES[13] (%0b) value is outside of legal range. USE_ADV_FEATURES[13] can be set to 1 only for packet mode in asynchronous AXI-Stream FIFO. %m", "XPM_FIFO_AXIS", 20, 8, EN_ADV_FEATURE_AXIS[13]); + drc_err_flag_axis = 1; + end + + // Infos + if (P_PKT_MODE == 1'b1 && EN_ADV_FEATURE_AXIS[3] != 1'b1) + $info("[%s %0d-%0d] Almost full flag option is not enabled (USE_ADV_FEATURES[3] = %0b) but Packet FIFO mode requires almost_full to be enabled. XPM_FIFO_AXIS enables the Almost full flag automatically. You may ignore almost_full port if not required %m", "XPM_FIFO_AXIS", 21, 1, EN_ADV_FEATURE_AXIS[3]); + + if (P_PKT_MODE == 1'b1 && EN_ADV_FEATURE_AXIS[11] != 1'b1) + $info("[%s %0d-%0d] Almost empty flag option is not enabled (USE_ADV_FEATURES[11] = %0b) but Packet FIFO mode requires almost_empty to be enabled. XPM_FIFO_AXIS enables the Almost empty flag automatically. You may ignore almost_empty port if not required %m", "XPM_FIFO_AXIS", 21, 1, EN_ADV_FEATURE_AXIS[11]); + + if (drc_err_flag_axis == 1) + #1 $finish; + end : config_drc_axis + + generate + if (P_ECC_MODE == 0) begin : axis_necc + assign axis_din = ({s_axis_tlast, s_axis_tuser, s_axis_tdest, s_axis_tid, s_axis_tkeep, s_axis_tstrb, s_axis_tdata}); + end // axis_necc + + if (P_ECC_MODE == 1) begin : axis_ecc + assign axis_din = ({{(AXIS_FINAL_DATA_WIDTH - AXIS_DATA_WIDTH){1'b0}},s_axis_tlast, s_axis_tuser, s_axis_tdest, s_axis_tid, s_axis_tkeep, s_axis_tstrb, s_axis_tdata}); + end // axis_ecc + + assign m_axis_tlast = axis_dout[AXIS_DATA_WIDTH-1]; + assign m_axis_tuser = axis_dout[TUSER_OFFSET-1:TDEST_OFFSET]; + assign m_axis_tdest = axis_dout[TDEST_OFFSET-1:TID_OFFSET]; + assign m_axis_tid = axis_dout[TID_OFFSET-1:TKEEP_OFFSET]; + assign m_axis_tkeep = axis_dout[TKEEP_OFFSET-1:TSTRB_OFFSET]; + assign m_axis_tstrb = axis_dout[TSTRB_OFFSET-1:TDATA_OFFSET]; + assign m_axis_tdata = axis_dout[TDATA_OFFSET-1:0]; + + // ------------------------------------------------------------------------------------------------------------------- + // Generate the instantiation of the appropriate XPM module + // ------------------------------------------------------------------------------------------------------------------- + if (EN_ADV_FEATURE_AXIS[15] == 1'b0) begin : gaxis_rst_sync + xpm_cdc_sync_rst #( + .DEST_SYNC_FF (P_COMMON_CLOCK?4:CDC_SYNC_STAGES), + .INIT (0), + .INIT_SYNC_FF (1), + .SIM_ASSERT_CHK (0) + ) xpm_cdc_sync_rst_inst ( + .src_rst (~s_aresetn), + .dest_clk (s_aclk), + .dest_rst (rst_axis) + ); + end // gaxis_rst_sync + if (EN_ADV_FEATURE_AXIS[15] == 1'b1) begin : gnaxis_rst_sync + assign rst_axis = s_aresetn; + end // gnaxis_rst_sync + + xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (RELATED_CLOCKS ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE ), + .ECC_MODE (P_ECC_MODE ), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH ), + .WRITE_DATA_WIDTH (AXIS_FINAL_DATA_WIDTH ), + .WR_DATA_COUNT_WIDTH (WR_DATA_COUNT_WIDTH ), + .PROG_FULL_THRESH (PROG_FULL_THRESH ), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES (USE_ADV_FEATURES_INT ), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (AXIS_FINAL_DATA_WIDTH ), + .RD_DATA_COUNT_WIDTH (RD_DATA_COUNT_WIDTH ), + .PROG_EMPTY_THRESH (PROG_EMPTY_THRESH ), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_inst ( + .sleep (1'b0), + .rst (rst_axis), + .wr_clk (s_aclk), + .wr_en (s_axis_tvalid), + .din (axis_din), + .full (), + .full_n (s_axis_tready), + .prog_full (prog_full_axis), + .wr_data_count (wr_data_count_axis), + .overflow (), + .wr_rst_busy (), + .almost_full (almost_full_axis), + .wr_ack (), + .rd_clk (P_COMMON_CLOCK?s_aclk:m_aclk), + .rd_en (m_axis_tvalid&m_axis_tready), + .dout (axis_dout), + .empty (), + .prog_empty (prog_empty_axis), + .rd_data_count (rd_data_count_axis), + .underflow (), + .rd_rst_busy (rd_rst_busy_axis), + .almost_empty (almost_empty_axis), + .data_valid (data_valid_axis), + .injectsbiterr (injectsbiterr_axis), + .injectdbiterr (injectdbiterr_axis), + .sbiterr (sbiterr_axis), + .dbiterr (dbiterr_axis) + ); + reg axis_pkt_read = 1'b0; + reg axis_wr_eop_d1 = 1'b0; + wire axis_wr_eop; + wire axis_rd_eop; + integer axis_pkt_cnt; + + if (P_PKT_MODE == 0) begin : gaxis_npkt_fifo + assign m_axis_tvalid = data_valid_axis; + end // gaxis_npkt_fifo + + if (P_PKT_MODE == 1 && P_COMMON_CLOCK == 1) begin : gaxis_pkt_fifo_cc + assign axis_wr_eop = s_axis_tvalid & s_axis_tready & s_axis_tlast; + assign axis_rd_eop = m_axis_tvalid & m_axis_tready & m_axis_tlast & axis_pkt_read; + assign m_axis_tvalid = data_valid_axis & axis_pkt_read; + + always @ (posedge s_aclk) begin + if (rst_axis) + axis_pkt_read <= 1'b0; + else if (axis_rd_eop && (axis_pkt_cnt == 1) && ~axis_wr_eop_d1) + axis_pkt_read <= 1'b0; + else if ((axis_pkt_cnt > 0) || (almost_full_axis && data_valid_axis)) + axis_pkt_read <= 1'b1; + end + + always @ (posedge s_aclk) begin + if (rst_axis) + axis_wr_eop_d1 <= 1'b0; + else + axis_wr_eop_d1 <= axis_wr_eop; + end + + always @ (posedge s_aclk) begin + if (rst_axis) + axis_pkt_cnt <= 0; + else if (axis_wr_eop_d1 && ~axis_rd_eop) + axis_pkt_cnt <= axis_pkt_cnt + 1; + else if (axis_rd_eop && ~axis_wr_eop_d1) + axis_pkt_cnt <= axis_pkt_cnt - 1; + end + end // gaxis_pkt_fifo_cc + + if (P_PKT_MODE == 1 && P_COMMON_CLOCK == 0) begin : gaxis_pkt_fifo_ic + wire [LOG_DEPTH_AXIS-1 : 0] axis_wpkt_cnt_rd_lt8_0; + wire [LOG_DEPTH_AXIS-1 : 0] axis_wpkt_cnt_rd_lt8_1; + wire [LOG_DEPTH_AXIS-1 : 0] axis_wpkt_cnt_rd_lt8_2; + wire [LOG_DEPTH_AXIS-1 : 0] axis_wpkt_cnt_rd; + reg [LOG_DEPTH_AXIS-1 : 0] axis_wpkt_cnt = 0; + reg [LOG_DEPTH_AXIS-1 : 0] axis_rpkt_cnt = 0; + wire [LOG_DEPTH_AXIS : 0] adj_axis_wpkt_cnt_rd_pad; + wire [LOG_DEPTH_AXIS : 0] rpkt_inv_pad; + wire [LOG_DEPTH_AXIS-1 : 0] diff_pkt_cnt; + reg [LOG_DEPTH_AXIS : 0] diff_pkt_cnt_pad = 0; + reg adj_axis_wpkt_cnt_rd_pad_0 = 0; + reg rpkt_inv_pad_0 = 0; + wire axis_af_rd ; + + assign axis_wr_eop = s_axis_tvalid & s_axis_tready & s_axis_tlast; + assign axis_rd_eop = m_axis_tvalid & m_axis_tready & m_axis_tlast & axis_pkt_read; + assign m_axis_tvalid = data_valid_axis & axis_pkt_read; + + always @ (posedge m_aclk) begin + if (rd_rst_busy_axis) + axis_pkt_read <= 1'b0; + else if (axis_rd_eop && (diff_pkt_cnt == 1)) + axis_pkt_read <= 1'b0; + else if ((diff_pkt_cnt > 0) || (axis_af_rd && data_valid_axis)) + axis_pkt_read <= 1'b1; + end + + always @ (posedge s_aclk) begin + if (rst_axis) + axis_wpkt_cnt <= 1'b0; + else if (axis_wr_eop) + axis_wpkt_cnt <= axis_wpkt_cnt + 1; + end + + xpm_cdc_gray #( + .DEST_SYNC_FF (CDC_SYNC_STAGES), + .INIT_SYNC_FF (1), + .REG_OUTPUT (1), + .WIDTH (LOG_DEPTH_AXIS)) + + wpkt_cnt_cdc_inst ( + .src_clk (s_aclk), + .src_in_bin (axis_wpkt_cnt), + .dest_clk (m_aclk), + .dest_out_bin (axis_wpkt_cnt_rd_lt8_0)); + + if (PKT_SIZE_LT8 == 1) begin : pkt_lt8 + xpm_fifo_reg_vec #(LOG_DEPTH_AXIS) + wpkt_cnt_rd_dly_inst1 (rd_rst_busy_axis, m_aclk, axis_wpkt_cnt_rd_lt8_0, axis_wpkt_cnt_rd_lt8_1); + xpm_fifo_reg_vec #(LOG_DEPTH_AXIS) + wpkt_cnt_rd_dly_inst2 (rd_rst_busy_axis, m_aclk, axis_wpkt_cnt_rd_lt8_1, axis_wpkt_cnt_rd_lt8_2); + xpm_fifo_reg_vec #(LOG_DEPTH_AXIS) + wpkt_cnt_rd_dly_inst3 (rd_rst_busy_axis, m_aclk, axis_wpkt_cnt_rd_lt8_2, axis_wpkt_cnt_rd); + end else begin : pkt_nlt8 + assign axis_wpkt_cnt_rd = axis_wpkt_cnt_rd_lt8_0; + end + + xpm_cdc_single #( + .DEST_SYNC_FF (CDC_SYNC_STAGES), + .SRC_INPUT_REG (0), + .INIT_SYNC_FF (1)) + + af_axis_cdc_inst ( + .src_clk (s_aclk), + .src_in (almost_full_axis), + .dest_clk (m_aclk), + .dest_out (axis_af_rd)); + + always @ (posedge m_aclk) begin + if (rd_rst_busy_axis) + axis_rpkt_cnt <= 1'b0; + else if (axis_rd_eop) + axis_rpkt_cnt <= axis_rpkt_cnt + 1; + end + + // Take the difference of write and read packet count using 1's complement + assign adj_axis_wpkt_cnt_rd_pad[LOG_DEPTH_AXIS : 1] = axis_wpkt_cnt_rd; + assign rpkt_inv_pad[LOG_DEPTH_AXIS : 1] = ~axis_rpkt_cnt; + assign adj_axis_wpkt_cnt_rd_pad[0] = adj_axis_wpkt_cnt_rd_pad_0; + assign rpkt_inv_pad[0] = rpkt_inv_pad_0; + + + always @ ( axis_rd_eop ) begin + if (!axis_rd_eop) begin + adj_axis_wpkt_cnt_rd_pad_0 <= 1'b1; + rpkt_inv_pad_0 <= 1'b1; + end else begin + adj_axis_wpkt_cnt_rd_pad_0 <= 1'b0; + rpkt_inv_pad_0 <= 1'b0; + end + end + + always @ (posedge m_aclk) begin + if (rd_rst_busy_axis) + diff_pkt_cnt_pad <= 1'b0; + else + diff_pkt_cnt_pad <= adj_axis_wpkt_cnt_rd_pad + rpkt_inv_pad ; + end + + assign diff_pkt_cnt = diff_pkt_cnt_pad [LOG_DEPTH_AXIS : 1] ; + + end // gaxis_pkt_fifo_ic + endgenerate + +endmodule : xpm_fifo_axis + +//******************************************************************************************************************** +//******************************************************************************************************************** +//******************************************************************************************************************** + + +(* XPM_MODULE = "TRUE", KEEP_HIERARCHY = "SOFT" *) +module xpm_fifo_axif + #( + parameter integer AXI_ID_WIDTH = 1, + parameter integer AXI_ADDR_WIDTH = 32, + parameter integer AXI_DATA_WIDTH = 32, + parameter integer AXI_LEN_WIDTH = 8, + parameter integer AXI_ARUSER_WIDTH = 1, + parameter integer AXI_AWUSER_WIDTH = 1, + parameter integer AXI_WUSER_WIDTH = 1, + parameter integer AXI_BUSER_WIDTH = 1, + parameter integer AXI_RUSER_WIDTH = 1, + parameter CLOCKING_MODE = "common", + parameter integer SIM_ASSERT_CHK = 0, + parameter integer CASCADE_HEIGHT = 0, + parameter integer CDC_SYNC_STAGES = 2, + parameter integer EN_RESET_SYNCHRONIZER = 0, + parameter PACKET_FIFO = "false", + parameter FIFO_MEMORY_TYPE_WACH = "lutram", + parameter FIFO_MEMORY_TYPE_WDCH = "bram", + parameter FIFO_MEMORY_TYPE_WRCH = "lutram", + parameter FIFO_MEMORY_TYPE_RACH = "lutram", + parameter FIFO_MEMORY_TYPE_RDCH = "bram", + parameter integer FIFO_DEPTH_WACH = 16, + parameter integer FIFO_DEPTH_WDCH = 16, + parameter integer FIFO_DEPTH_WRCH = 2048, + parameter integer FIFO_DEPTH_RACH = 16, + parameter integer FIFO_DEPTH_RDCH = 2048, + parameter ECC_MODE_WDCH = "no_ecc", + parameter ECC_MODE_RDCH = "no_ecc", + parameter USE_ADV_FEATURES_WDCH = "1000", + parameter USE_ADV_FEATURES_RDCH = "1000", + parameter integer WR_DATA_COUNT_WIDTH_WDCH = 10, + parameter integer WR_DATA_COUNT_WIDTH_RDCH = 10, + parameter integer RD_DATA_COUNT_WIDTH_WDCH = 10, + parameter integer RD_DATA_COUNT_WIDTH_RDCH = 10, + parameter integer PROG_FULL_THRESH_WDCH = 10, + parameter integer PROG_FULL_THRESH_RDCH = 10, + parameter integer PROG_EMPTY_THRESH_WDCH = 10, + parameter integer PROG_EMPTY_THRESH_RDCH = 10 + + ) + ( + // AXI Global Signal + input wire m_aclk, + input wire s_aclk, + input wire s_aresetn, + + // AXI Full/Lite Slave Write Channel (write side) + input wire [AXI_ID_WIDTH-1:0] s_axi_awid, + input wire [AXI_ADDR_WIDTH-1:0] s_axi_awaddr, + input wire [AXI_LEN_WIDTH-1:0] s_axi_awlen, + input wire [3-1:0] s_axi_awsize, + input wire [2-1:0] s_axi_awburst, + input wire [2-1:0] s_axi_awlock, + input wire [4-1:0] s_axi_awcache, + input wire [3-1:0] s_axi_awprot, + input wire [4-1:0] s_axi_awqos, + input wire [4-1:0] s_axi_awregion, + input wire [AXI_AWUSER_WIDTH-1:0] s_axi_awuser, + input wire s_axi_awvalid, + output wire s_axi_awready, + input wire [AXI_DATA_WIDTH-1:0] s_axi_wdata, + input wire [AXI_DATA_WIDTH/8-1:0] s_axi_wstrb, + input wire s_axi_wlast, + input wire [AXI_WUSER_WIDTH-1:0] s_axi_wuser, + input wire s_axi_wvalid, + output wire s_axi_wready, + output wire [AXI_ID_WIDTH-1:0] s_axi_bid, + output wire [2-1:0] s_axi_bresp, + output wire [AXI_BUSER_WIDTH-1:0] s_axi_buser, + output wire s_axi_bvalid, + input wire s_axi_bready, + + // AXI Full/Lite Master Write Channel (read side) + output wire [AXI_ID_WIDTH-1:0] m_axi_awid, + output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr, + output wire [AXI_LEN_WIDTH-1:0] m_axi_awlen, + output wire [3-1:0] m_axi_awsize, + output wire [2-1:0] m_axi_awburst, + output wire [2-1:0] m_axi_awlock, + output wire [4-1:0] m_axi_awcache, + output wire [3-1:0] m_axi_awprot, + output wire [4-1:0] m_axi_awqos, + output wire [4-1:0] m_axi_awregion, + output wire [AXI_AWUSER_WIDTH-1:0] m_axi_awuser, + output wire m_axi_awvalid, + input wire m_axi_awready, + output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata, + output wire [AXI_DATA_WIDTH/8-1:0] m_axi_wstrb, + output wire m_axi_wlast, + output wire [AXI_WUSER_WIDTH-1:0] m_axi_wuser, + output wire m_axi_wvalid, + input wire m_axi_wready, + input wire [AXI_ID_WIDTH-1:0] m_axi_bid, + input wire [2-1:0] m_axi_bresp, + input wire [AXI_BUSER_WIDTH-1:0] m_axi_buser, + input wire m_axi_bvalid, + output wire m_axi_bready, + + // AXI Full/Lite Slave Read Channel (write side) + input wire [AXI_ID_WIDTH-1:0] s_axi_arid, + input wire [AXI_ADDR_WIDTH-1:0] s_axi_araddr, + input wire [AXI_LEN_WIDTH-1:0] s_axi_arlen, + input wire [3-1:0] s_axi_arsize, + input wire [2-1:0] s_axi_arburst, + input wire [2-1:0] s_axi_arlock, + input wire [4-1:0] s_axi_arcache, + input wire [3-1:0] s_axi_arprot, + input wire [4-1:0] s_axi_arqos, + input wire [4-1:0] s_axi_arregion, + input wire [AXI_ARUSER_WIDTH-1:0] s_axi_aruser, + input wire s_axi_arvalid, + output wire s_axi_arready, + output wire [AXI_ID_WIDTH-1:0] s_axi_rid, + output wire [AXI_DATA_WIDTH-1:0] s_axi_rdata, + output wire [2-1:0] s_axi_rresp, + output wire s_axi_rlast, + output wire [AXI_RUSER_WIDTH-1:0] s_axi_ruser, + output wire s_axi_rvalid, + input wire s_axi_rready, + + // AXI Full/Lite Master Read Channel (read side) + output wire [AXI_ID_WIDTH-1:0] m_axi_arid, + output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr, + output wire [AXI_LEN_WIDTH-1:0] m_axi_arlen, + output wire [3-1:0] m_axi_arsize, + output wire [2-1:0] m_axi_arburst, + output wire [2-1:0] m_axi_arlock, + output wire [4-1:0] m_axi_arcache, + output wire [3-1:0] m_axi_arprot, + output wire [4-1:0] m_axi_arqos, + output wire [4-1:0] m_axi_arregion, + output wire [AXI_ARUSER_WIDTH-1:0] m_axi_aruser, + output wire m_axi_arvalid, + input wire m_axi_arready, + input wire [AXI_ID_WIDTH-1:0] m_axi_rid, + input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata, + input wire [2-1:0] m_axi_rresp, + input wire m_axi_rlast, + input wire [AXI_RUSER_WIDTH-1:0] m_axi_ruser, + input wire m_axi_rvalid, + output wire m_axi_rready, + + // AXI4-Full Sideband Signals + output wire prog_full_wdch, + output wire prog_empty_wdch, + output wire [WR_DATA_COUNT_WIDTH_WDCH-1:0] wr_data_count_wdch, + output wire [RD_DATA_COUNT_WIDTH_WDCH-1:0] rd_data_count_wdch, + output wire prog_full_rdch, + output wire prog_empty_rdch, + output wire [WR_DATA_COUNT_WIDTH_RDCH-1:0] wr_data_count_rdch, + output wire [RD_DATA_COUNT_WIDTH_RDCH-1:0] rd_data_count_rdch, + + // ECC Related ports + input wire injectsbiterr_wdch, + input wire injectdbiterr_wdch, + output wire sbiterr_wdch, + output wire dbiterr_wdch, + input wire injectsbiterr_rdch, + input wire injectdbiterr_rdch, + output wire sbiterr_rdch, + output wire dbiterr_rdch + + ); + + + // Function to convert ASCII value to binary + function [3:0] str2bin; + input [7:0] str_val_ascii; + if((str_val_ascii == 8'h30) || (str_val_ascii == 8'h31) || + (str_val_ascii == 8'h32) || (str_val_ascii == 8'h33) || + (str_val_ascii == 8'h34) || (str_val_ascii == 8'h35) || + (str_val_ascii == 8'h36) || (str_val_ascii == 8'h37) || + (str_val_ascii == 8'h38) || (str_val_ascii == 8'h39) || + (str_val_ascii == 8'h41) || (str_val_ascii == 8'h42) || + (str_val_ascii == 8'h43) || (str_val_ascii == 8'h44) || + (str_val_ascii == 8'h45) || (str_val_ascii == 8'h46) || + (str_val_ascii == 8'h61) || (str_val_ascii == 8'h62) || + (str_val_ascii == 8'h63) || (str_val_ascii == 8'h64) || + (str_val_ascii == 8'h65) || (str_val_ascii == 8'h66) || + (str_val_ascii == 8'h00)) begin + if (!str_val_ascii[6]) + str2bin = str_val_ascii[3:0]; + else begin + str2bin [3] = 1'b1; + str2bin [2] = str_val_ascii[2] | (str_val_ascii[1] & str_val_ascii[0]); + str2bin [1] = str_val_ascii[0] ^ str_val_ascii[1]; + str2bin [0] = !str_val_ascii[0]; + end + end + else + $error("Found Invalid character while parsing the string, please cross check the value specified for either READ_RESET_VALUE_A|B or MEMORY_INIT_PARAM (if initialization of memory through parameter is used). XPM_MEMORY supports strings (hex) that contains characters 0-9, A-F and a-f."); + endfunction + // Function that parses the complete reset value string + function logic [15:0] hstr2bin; + input [16*8-1 : 0] hstr_val; + integer rst_loop_a; + localparam integer rsta_loop_iter = 16; + logic [rsta_loop_iter-1 : 0] rst_val_conv_a_i; + for (rst_loop_a=1; rst_loop_a <= rsta_loop_iter/4; rst_loop_a = rst_loop_a+1) begin + rst_val_conv_a_i[(rst_loop_a*4)-1 -: 4] = str2bin(hstr_val[(rst_loop_a*8)-1 -: 8]); + end + return rst_val_conv_a_i[15:0]; + endfunction + +//Function to convert binary to ASCII value + function [7:0] bin2str; + input [3:0] bin_val; + if( bin_val > 4'h9) begin + bin2str [7:4] = 4'h4; + bin2str [3] = 1'b0; + bin2str [2:0] = bin_val[2:0]-1'b1; + end + else begin + bin2str [7:4] = 4'h3; + bin2str [3:0] = bin_val; + end + endfunction + + // Function that parses the complete binary value to string + function [31:0] bin2hstr; + input [15 : 0] bin_val; + integer str_pos; + localparam integer str_max_bits = 32; + for (str_pos=1; str_pos <= str_max_bits/8; str_pos = str_pos+1) begin + bin2hstr[(str_pos*8)-1 -: 8] = bin2str(bin_val[(str_pos*4)-1 -: 4]); + end + endfunction + +//WDCH advanced features parameter conversion + localparam [15:0] EN_ADV_FEATURE_WDCH = hstr2bin(USE_ADV_FEATURES_WDCH); + localparam EN_ALMOST_FULL_INT_WDCH = (PACKET_FIFO == "true") ? 1'b1 : EN_ADV_FEATURE_WDCH[3]; + localparam EN_ALMOST_EMPTY_INT_WDCH = (PACKET_FIFO == "true") ? 1'b1 : EN_ADV_FEATURE_WDCH[11]; + localparam EN_DATA_VALID_INT = 1'b1; + localparam [15:0] EN_ADV_FEATURE_WDCH_INT = {EN_ADV_FEATURE_WDCH[15:13], EN_DATA_VALID_INT, EN_ALMOST_EMPTY_INT_WDCH, EN_ADV_FEATURE_WDCH[10:4], EN_ALMOST_FULL_INT_WDCH, EN_ADV_FEATURE_WDCH[2:0]}; + localparam USE_ADV_FEATURES_WDCH_INT = bin2hstr(EN_ADV_FEATURE_WDCH_INT); + + +//RDCH advanced features parameter conversion + localparam [15:0] EN_ADV_FEATURE_RDCH = hstr2bin(USE_ADV_FEATURES_RDCH); + localparam EN_ALMOST_FULL_INT_RDCH = (PACKET_FIFO == "true") ? 1'b1 : EN_ADV_FEATURE_RDCH[3]; + localparam EN_ALMOST_EMPTY_INT_RDCH = (PACKET_FIFO == "true") ? 1'b1 : EN_ADV_FEATURE_RDCH[11]; + localparam [15:0] EN_ADV_FEATURE_RDCH_INT = {EN_ADV_FEATURE_RDCH[15:13], EN_DATA_VALID_INT, EN_ALMOST_EMPTY_INT_RDCH, EN_ADV_FEATURE_RDCH[10:4], EN_ALMOST_FULL_INT_RDCH, EN_ADV_FEATURE_RDCH[2:0]}; + localparam USE_ADV_FEATURES_RDCH_INT = bin2hstr(EN_ADV_FEATURE_RDCH_INT); + + + localparam C_AXI_LOCK_WIDTH = 2; + // AXI Channel Type + // WACH --> Write Address Channel + // WDCH --> Write Data Channel + // WRCH --> Write Response Channel + // RACH --> Read Address Channel + // RDCH --> Read Data Channel + localparam C_WACH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logic + localparam C_WDCH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logie + localparam C_WRCH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logie + localparam C_RACH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logie + localparam C_RDCH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logie + + // Input Data Width + // Accumulation of all AXI input signal's width + localparam C_DIN_WIDTH_WACH = AXI_ID_WIDTH+AXI_ADDR_WIDTH+AXI_AWUSER_WIDTH+AXI_LEN_WIDTH+C_AXI_LOCK_WIDTH+20; + localparam C_DIN_WIDTH_WDCH = AXI_DATA_WIDTH/8+AXI_DATA_WIDTH+AXI_WUSER_WIDTH+1; + localparam C_DIN_WIDTH_WRCH = AXI_ID_WIDTH+AXI_BUSER_WIDTH+2; + localparam C_DIN_WIDTH_RACH = AXI_ID_WIDTH+AXI_ADDR_WIDTH+AXI_ARUSER_WIDTH+AXI_LEN_WIDTH+C_AXI_LOCK_WIDTH+20; + localparam C_DIN_WIDTH_RDCH = AXI_ID_WIDTH+AXI_DATA_WIDTH+AXI_RUSER_WIDTH+3; + + + // Define local parameters for mapping with base file + localparam integer P_COMMON_CLOCK = ( (CLOCKING_MODE == "common_clock" || CLOCKING_MODE == "COMMON_CLOCK" || CLOCKING_MODE == "COMMON" || CLOCKING_MODE == "common") ? 1 : + ( (CLOCKING_MODE == "independent_clock" || CLOCKING_MODE == "INDEPENDENT_CLOCK" || CLOCKING_MODE == "INDEPENDENT" || CLOCKING_MODE == "independent") ? 0 : 2)); + + localparam integer P_ECC_MODE_WDCH = ( (ECC_MODE_WDCH == "no_ecc" || ECC_MODE_WDCH == "NO_ECC" ) ? 0 : 1); + localparam integer P_ECC_MODE_RDCH = ( (ECC_MODE_RDCH == "no_ecc" || ECC_MODE_RDCH == "NO_ECC" ) ? 0 : 1); + localparam integer P_FIFO_MEMORY_TYPE_WACH = ( (FIFO_MEMORY_TYPE_WACH == "lutram" || FIFO_MEMORY_TYPE_WACH == "LUTRAM" || FIFO_MEMORY_TYPE_WACH == "distributed" || FIFO_MEMORY_TYPE_WACH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_WACH == "blockram" || FIFO_MEMORY_TYPE_WACH == "BLOCKRAM" || FIFO_MEMORY_TYPE_WACH == "bram" || FIFO_MEMORY_TYPE_WACH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_WACH == "ultraram" || FIFO_MEMORY_TYPE_WACH == "ULTRARAM" || FIFO_MEMORY_TYPE_WACH == "uram" || FIFO_MEMORY_TYPE_WACH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_WACH == "builtin" || FIFO_MEMORY_TYPE_WACH == "BUILTIN") ? 4 : 0)))); + localparam integer P_FIFO_MEMORY_TYPE_WDCH = ( (FIFO_MEMORY_TYPE_WDCH == "lutram" || FIFO_MEMORY_TYPE_WDCH == "LUTRAM" || FIFO_MEMORY_TYPE_WDCH == "distributed" || FIFO_MEMORY_TYPE_WDCH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_WDCH == "blockram" || FIFO_MEMORY_TYPE_WDCH == "BLOCKRAM" || FIFO_MEMORY_TYPE_WDCH == "bram" || FIFO_MEMORY_TYPE_WDCH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_WDCH == "ultraram" || FIFO_MEMORY_TYPE_WDCH == "ULTRARAM" || FIFO_MEMORY_TYPE_WDCH == "uram" || FIFO_MEMORY_TYPE_WDCH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_WDCH == "builtin" || FIFO_MEMORY_TYPE_WDCH == "BUILTIN") ? 4 : 0)))); + localparam integer P_FIFO_MEMORY_TYPE_WRCH = ( (FIFO_MEMORY_TYPE_WRCH == "lutram" || FIFO_MEMORY_TYPE_WRCH == "LUTRAM" || FIFO_MEMORY_TYPE_WRCH == "distributed" || FIFO_MEMORY_TYPE_WRCH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_WRCH == "blockram" || FIFO_MEMORY_TYPE_WRCH == "BLOCKRAM" || FIFO_MEMORY_TYPE_WRCH == "bram" || FIFO_MEMORY_TYPE_WRCH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_WRCH == "ultraram" || FIFO_MEMORY_TYPE_WRCH == "ULTRARAM" || FIFO_MEMORY_TYPE_WRCH == "uram" || FIFO_MEMORY_TYPE_WRCH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_WRCH == "builtin" || FIFO_MEMORY_TYPE_WRCH == "BUILTIN") ? 4 : 0)))); + localparam integer P_FIFO_MEMORY_TYPE_RACH = ( (FIFO_MEMORY_TYPE_RACH == "lutram" || FIFO_MEMORY_TYPE_RACH == "LUTRAM" || FIFO_MEMORY_TYPE_RACH == "distributed" || FIFO_MEMORY_TYPE_RACH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_RACH == "blockram" || FIFO_MEMORY_TYPE_RACH == "BLOCKRAM" || FIFO_MEMORY_TYPE_RACH == "bram" || FIFO_MEMORY_TYPE_RACH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_RACH == "ultraram" || FIFO_MEMORY_TYPE_RACH == "ULTRARAM" || FIFO_MEMORY_TYPE_RACH == "uram" || FIFO_MEMORY_TYPE_RACH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_RACH == "builtin" || FIFO_MEMORY_TYPE_RACH == "BUILTIN") ? 4 : 0)))); + localparam integer P_FIFO_MEMORY_TYPE_RDCH = ( (FIFO_MEMORY_TYPE_RDCH == "lutram" || FIFO_MEMORY_TYPE_RDCH == "LUTRAM" || FIFO_MEMORY_TYPE_RDCH == "distributed" || FIFO_MEMORY_TYPE_RDCH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_RDCH == "blockram" || FIFO_MEMORY_TYPE_RDCH == "BLOCKRAM" || FIFO_MEMORY_TYPE_RDCH == "bram" || FIFO_MEMORY_TYPE_RDCH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_RDCH == "ultraram" || FIFO_MEMORY_TYPE_RDCH == "ULTRARAM" || FIFO_MEMORY_TYPE_RDCH == "uram" || FIFO_MEMORY_TYPE_RDCH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_RDCH == "builtin" || FIFO_MEMORY_TYPE_RDCH == "BUILTIN") ? 4 : 0)))); + + + localparam C_DIN_WIDTH_WDCH_ECC = (P_ECC_MODE_WDCH == 0) ? C_DIN_WIDTH_WDCH : ((C_DIN_WIDTH_WDCH%64 == 0) ? C_DIN_WIDTH_WDCH : (64*(C_DIN_WIDTH_WDCH/64+1))); + localparam C_DIN_WIDTH_RDCH_ECC = (P_ECC_MODE_RDCH == 0) ? C_DIN_WIDTH_RDCH : ((C_DIN_WIDTH_RDCH%64 == 0) ? C_DIN_WIDTH_RDCH : (64*(C_DIN_WIDTH_RDCH/64+1))); + + + wire wr_rst_busy_wach; + wire wr_rst_busy_wdch; + wire wr_rst_busy_wrch; + wire wr_rst_busy_rach; + wire wr_rst_busy_rdch; + + + + + + + + + + + localparam C_AXI_SIZE_WIDTH = 3; + localparam C_AXI_BURST_WIDTH = 2; + localparam C_AXI_CACHE_WIDTH = 4; + localparam C_AXI_PROT_WIDTH = 3; + localparam C_AXI_QOS_WIDTH = 4; + localparam C_AXI_REGION_WIDTH = 4; + localparam C_AXI_BRESP_WIDTH = 2; + localparam C_AXI_RRESP_WIDTH = 2; + + + wire inverted_reset = ~s_aresetn; + wire rst_axif_sclk; + wire rst_axif_mclk; + wire m_aclk_int; + assign m_aclk_int = P_COMMON_CLOCK ? s_aclk : m_aclk; + + generate + if (EN_RESET_SYNCHRONIZER == 1) begin : gen_sync_reset +//Reset Synchronizer + xpm_cdc_sync_rst #( + .DEST_SYNC_FF (P_COMMON_CLOCK ? 4 : CDC_SYNC_STAGES), + .INIT (0), + .INIT_SYNC_FF (1), + .SIM_ASSERT_CHK (0) + ) xpm_cdc_sync_rst_sclk_inst ( + .src_rst (~s_aresetn), + .dest_clk (s_aclk), + .dest_rst (rst_axif_sclk) + ); + xpm_cdc_sync_rst #( + .DEST_SYNC_FF (P_COMMON_CLOCK ? 4 : CDC_SYNC_STAGES), + .INIT (0), + .INIT_SYNC_FF (1), + .SIM_ASSERT_CHK (0) + ) xpm_cdc_sync_rst_mclk_inst ( + .src_rst (~s_aresetn), + .dest_clk (m_aclk_int), + .dest_rst (rst_axif_mclk) + ); + end // gen_sync_reset + if (EN_RESET_SYNCHRONIZER == 0) begin : gen_async_reset + assign rst_axif_sclk = inverted_reset; + assign rst_axif_mclk = inverted_reset; + + end // gen_async_reset + endgenerate + + + //########################################################################### + // AXI FULL Write Channel (axi_write_channel) + //########################################################################### + + + localparam IS_AXI_FULL_WACH = ((C_WACH_TYPE == 0)) ? 1 : 0; + localparam IS_AXI_FULL_WDCH = ((C_WDCH_TYPE == 0)) ? 1 : 0; + localparam IS_AXI_FULL_WRCH = ((C_WRCH_TYPE == 0)) ? 1 : 0; + localparam IS_AXI_FULL_RACH = ((C_RACH_TYPE == 0)) ? 1 : 0; + localparam IS_AXI_FULL_RDCH = ((C_RDCH_TYPE == 0)) ? 1 : 0; + + localparam IS_WR_ADDR_CH = (IS_AXI_FULL_WACH == 1) ? 1 : 0; + localparam IS_WR_DATA_CH = (IS_AXI_FULL_WDCH == 1) ? 1 : 0; + localparam IS_WR_RESP_CH = (IS_AXI_FULL_WRCH == 1) ? 1 : 0; + localparam IS_RD_ADDR_CH = (IS_AXI_FULL_RACH == 1) ? 1 : 0; + localparam IS_RD_DATA_CH = (IS_AXI_FULL_RDCH == 1) ? 1 : 0; + + localparam AWID_OFFSET = C_DIN_WIDTH_WACH - AXI_ID_WIDTH ; + localparam AWADDR_OFFSET = AWID_OFFSET - AXI_ADDR_WIDTH; + localparam AWLEN_OFFSET = AWADDR_OFFSET - AXI_LEN_WIDTH ; + localparam AWSIZE_OFFSET = AWLEN_OFFSET - C_AXI_SIZE_WIDTH ; + localparam AWBURST_OFFSET = AWSIZE_OFFSET - C_AXI_BURST_WIDTH ; + localparam AWLOCK_OFFSET = AWBURST_OFFSET - C_AXI_LOCK_WIDTH ; + localparam AWCACHE_OFFSET = AWLOCK_OFFSET - C_AXI_CACHE_WIDTH ; + localparam AWPROT_OFFSET = AWCACHE_OFFSET - C_AXI_PROT_WIDTH; + localparam AWQOS_OFFSET = AWPROT_OFFSET - C_AXI_QOS_WIDTH; + localparam AWREGION_OFFSET = AWQOS_OFFSET - C_AXI_REGION_WIDTH ; + localparam AWUSER_OFFSET = AWREGION_OFFSET-AXI_AWUSER_WIDTH ; + + localparam WID_OFFSET = C_DIN_WIDTH_WDCH; + localparam WDATA_OFFSET = WID_OFFSET - AXI_DATA_WIDTH; + localparam WSTRB_OFFSET = WDATA_OFFSET - AXI_DATA_WIDTH/8; + localparam WUSER_OFFSET = WSTRB_OFFSET-AXI_WUSER_WIDTH ; + + localparam BID_OFFSET = C_DIN_WIDTH_WRCH - AXI_ID_WIDTH ; + localparam BRESP_OFFSET = BID_OFFSET - C_AXI_BRESP_WIDTH; + localparam BUSER_OFFSET = BRESP_OFFSET-AXI_BUSER_WIDTH; + + + wire [C_DIN_WIDTH_WACH-1:0] wach_din ; + wire [C_DIN_WIDTH_WACH-1:0] wach_dout ; + wire [C_DIN_WIDTH_WACH-1:0] wach_dout_pkt ; + wire wach_full ; + wire wach_almost_full ; + wire wach_prog_full ; + wire wach_empty ; + wire wach_almost_empty ; + wire wach_prog_empty ; + wire [C_DIN_WIDTH_WDCH_ECC-1:0] wdch_din ; + wire [C_DIN_WIDTH_WDCH_ECC-1:0] wdch_dout ; + wire wdch_full ; + wire wdch_almost_full ; + wire wdch_prog_full ; + wire wdch_empty ; + wire wdch_almost_empty ; + wire wdch_prog_empty ; + wire [C_DIN_WIDTH_WRCH-1:0] wrch_din ; + wire [C_DIN_WIDTH_WRCH-1:0] wrch_dout ; + wire wrch_full ; + wire wrch_almost_full ; + wire wrch_prog_full ; + wire wrch_empty ; + wire wrch_almost_empty ; + wire wrch_prog_empty ; + wire axi_aw_underflow_i; + wire axi_w_underflow_i ; + wire axi_b_underflow_i ; + wire axi_aw_overflow_i ; + wire axi_w_overflow_i ; + wire axi_b_overflow_i ; + wire wach_s_axi_awready; + wire wach_m_axi_awvalid; + wire wach_rd_en ; + wire wdch_s_axi_wready ; + wire wdch_m_axi_wvalid ; + wire wdch_wr_en ; + wire wdch_rd_en ; + wire wrch_s_axi_bvalid ; + wire wrch_m_axi_bready ; + wire txn_count_up ; + wire txn_count_down ; + wire awvalid_en ; + wire awvalid_pkt ; + wire awready_pkt ; + integer wr_pkt_count ; + wire wach_re ; + wire wdch_we ; + wire wdch_re ; + + generate if (IS_WR_ADDR_CH == 1) begin : axi_write_address_channel + // Write protection when almost full or prog_full is high + + // Read protection when almost empty or prog_empty is high + assign wach_re = (PACKET_FIFO == "true") ? awready_pkt & awvalid_en : m_axi_awready; + assign wach_rd_en = wach_re; + + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_WACH), + .ECC_MODE (0), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_WACH ), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_WACH ), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES ("0101"), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_WACH ), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_wach_dut ( + .sleep (1'b0), + .rst (rst_axif_sclk), + .wr_clk (s_aclk), + .wr_en (s_axi_awvalid), + .din (wach_din), + .full (wach_full), + .full_n (), + .prog_full (), + .wr_data_count (), + .overflow (axi_aw_overflow_i), + .wr_rst_busy (wr_rst_busy_wach), + .almost_full (), + .wr_ack (), + .rd_clk (m_aclk_int), + .rd_en (wach_rd_en), + .dout (wach_dout_pkt), + .empty (wach_empty), + .prog_empty (), + .rd_data_count (), + .underflow (axi_aw_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (1'b0), + .injectdbiterr (1'b0), + .sbiterr (), + .dbiterr () + ); + + assign wach_s_axi_awready = (FIFO_MEMORY_TYPE_WACH == "lutram") ? ~(wach_full | wr_rst_busy_wach) : ~wach_full; + assign wach_m_axi_awvalid = ~wach_empty; + assign s_axi_awready = wach_s_axi_awready; + + + end endgenerate // axi_write_address_channel + + + generate if (PACKET_FIFO == "true") begin : axi_mm_pkt_fifo_wr + + xpm_fifo_axi_reg_slice + #( + .C_DATA_WIDTH (C_DIN_WIDTH_WACH), + .C_REG_CONFIG (1) + ) + wach_pkt_reg_slice_inst + ( + // System Signals + .ACLK (s_aclk), + .ARESET (rst_axif_sclk), + + // Slave side + .S_PAYLOAD_DATA (wach_dout_pkt), + .S_VALID (awvalid_pkt), + .S_READY (awready_pkt), + + // Master side + .M_PAYLOAD_DATA (wach_dout), + .M_VALID (m_axi_awvalid), + .M_READY (m_axi_awready) + ); + + assign awvalid_pkt = wach_m_axi_awvalid && awvalid_en; + + assign txn_count_up = wdch_s_axi_wready && wdch_wr_en && wdch_din[0]; + assign txn_count_down = wach_m_axi_awvalid && awready_pkt && awvalid_en; + + always@(posedge s_aclk ) begin + if(rst_axif_sclk == 1) begin + wr_pkt_count <= 0; + end else begin + if(txn_count_up == 1 && txn_count_down == 0) begin + wr_pkt_count <= wr_pkt_count + 1; + end else if(txn_count_up == 0 && txn_count_down == 1) begin + wr_pkt_count <= wr_pkt_count - 1; + end + end + end //Always end + assign awvalid_en = (wr_pkt_count > 0)? 1:0; + end endgenerate + + generate if (PACKET_FIFO == "false") begin : axi_mm_fifo_wr + assign awvalid_en = 1; + assign wach_dout = wach_dout_pkt; + assign m_axi_awvalid = wach_m_axi_awvalid; + end + endgenerate + + + + generate if (IS_WR_DATA_CH == 1) begin : axi_write_data_channel + // Write protection when almost full or prog_full is high + assign wdch_we = wdch_s_axi_wready & s_axi_wvalid ; + + // Read protection when almost empty or prog_empty is high + assign wdch_re = wdch_m_axi_wvalid & m_axi_wready ; + assign wdch_wr_en = wdch_we; + assign wdch_rd_en = wdch_re; + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_WDCH), + .ECC_MODE (P_ECC_MODE_WDCH), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_WDCH), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_WDCH_ECC), + .WR_DATA_COUNT_WIDTH (WR_DATA_COUNT_WIDTH_WDCH), + .PROG_FULL_THRESH (PROG_FULL_THRESH_WDCH), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES (USE_ADV_FEATURES_WDCH_INT), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_WDCH_ECC), + .RD_DATA_COUNT_WIDTH (RD_DATA_COUNT_WIDTH_WDCH), + .PROG_EMPTY_THRESH (PROG_EMPTY_THRESH_WDCH), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_wdch_dut ( + .sleep (1'b0), + .rst (rst_axif_sclk), + .wr_clk (s_aclk), + .wr_en (wdch_wr_en), + .din (wdch_din), + .full (wdch_full), + .full_n (), + .prog_full (prog_full_wdch), + .wr_data_count (wr_data_count_wdch), + .overflow (axi_w_overflow_i), + .wr_rst_busy (wr_rst_busy_wdch), + .almost_full (), + .wr_ack (), + .rd_clk (m_aclk_int), + .rd_en (wdch_rd_en), + .dout (wdch_dout), + .empty (wdch_empty), + .prog_empty (prog_empty_wdch), + .rd_data_count (rd_data_count_wdch), + .underflow (axi_w_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (injectsbiterr_wdch), + .injectdbiterr (injectdbiterr_wdch), + .sbiterr (sbiterr_wdch), + .dbiterr (dbiterr_wdch) + ); + + + assign wdch_s_axi_wready = (FIFO_MEMORY_TYPE_WDCH == "lutram") ? ~(wdch_full | wr_rst_busy_wdch) : ~wdch_full; + assign wdch_m_axi_wvalid = ~wdch_empty; + assign s_axi_wready = wdch_s_axi_wready; + assign m_axi_wvalid = wdch_m_axi_wvalid; + + + end endgenerate // axi_write_data_channel + + + generate if (IS_WR_RESP_CH == 1) begin : axi_write_resp_channel + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_WRCH), + .ECC_MODE (0), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_WRCH ), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_WRCH), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES ("0101"), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_WRCH), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_wrch_dut ( + .sleep (1'b0), + .rst (rst_axif_mclk), + .wr_clk (m_aclk_int), + .wr_en (m_axi_bvalid), + .din (wrch_din), + .full (wrch_full), + .full_n (), + .prog_full (), + .wr_data_count (), + .overflow (axi_b_overflow_i), + .wr_rst_busy (wr_rst_busy_wrch), + .almost_full (), + .wr_ack (), + .rd_clk (s_aclk), + .rd_en (s_axi_bready), + .dout (wrch_dout), + .empty (wrch_empty), + .prog_empty (), + .rd_data_count (), + .underflow (axi_b_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (1'b0), + .injectdbiterr (1'b0), + .sbiterr (), + .dbiterr () + ); + + assign wrch_s_axi_bvalid = ~wrch_empty; + assign wrch_m_axi_bready = (FIFO_MEMORY_TYPE_WRCH == "lutram") ? ~(wrch_full | wr_rst_busy_wrch) : ~wrch_full; + assign s_axi_bvalid = wrch_s_axi_bvalid; + assign m_axi_bready = wrch_m_axi_bready; + + end endgenerate // axi_write_resp_channel + + + + + generate if (IS_AXI_FULL_WACH == 1 || (C_WACH_TYPE == 1)) begin : axi_wach_output + assign m_axi_awaddr = wach_dout[AWID_OFFSET-1:AWADDR_OFFSET]; + assign m_axi_awlen = wach_dout[AWADDR_OFFSET-1:AWLEN_OFFSET]; + assign m_axi_awsize = wach_dout[AWLEN_OFFSET-1:AWSIZE_OFFSET]; + assign m_axi_awburst = wach_dout[AWSIZE_OFFSET-1:AWBURST_OFFSET]; + assign m_axi_awlock = wach_dout[AWBURST_OFFSET-1:AWLOCK_OFFSET]; + assign m_axi_awcache = wach_dout[AWLOCK_OFFSET-1:AWCACHE_OFFSET]; + assign m_axi_awprot = wach_dout[AWCACHE_OFFSET-1:AWPROT_OFFSET]; + assign m_axi_awqos = wach_dout[AWPROT_OFFSET-1:AWQOS_OFFSET]; + assign wach_din[AWID_OFFSET-1:AWADDR_OFFSET] = s_axi_awaddr; + assign wach_din[AWADDR_OFFSET-1:AWLEN_OFFSET] = s_axi_awlen; + assign wach_din[AWLEN_OFFSET-1:AWSIZE_OFFSET] = s_axi_awsize; + assign wach_din[AWSIZE_OFFSET-1:AWBURST_OFFSET] = s_axi_awburst; + assign wach_din[AWBURST_OFFSET-1:AWLOCK_OFFSET] = s_axi_awlock; + assign wach_din[AWLOCK_OFFSET-1:AWCACHE_OFFSET] = s_axi_awcache; + assign wach_din[AWCACHE_OFFSET-1:AWPROT_OFFSET] = s_axi_awprot; + assign wach_din[AWPROT_OFFSET-1:AWQOS_OFFSET] = s_axi_awqos; + end endgenerate // axi_wach_output + + generate if ((IS_AXI_FULL_WACH == 1 || (C_WACH_TYPE == 1))) begin : axi_awregion + assign m_axi_awregion = wach_dout[AWQOS_OFFSET-1:AWREGION_OFFSET]; + end endgenerate // axi_awregion + + generate if ((IS_AXI_FULL_WACH == 1 || (C_WACH_TYPE == 1))) begin : axi_awuser + assign m_axi_awuser = wach_dout[AWREGION_OFFSET-1:AWUSER_OFFSET]; + end endgenerate // axi_awuser + + + generate if ((IS_AXI_FULL_WACH == 1 || (C_WACH_TYPE == 1))) begin : axi_awid + assign m_axi_awid = wach_dout[C_DIN_WIDTH_WACH-1:AWID_OFFSET]; + end endgenerate //axi_awid + + generate if (IS_AXI_FULL_WDCH == 1 || (C_WDCH_TYPE == 1)) begin : axi_wdch_output + assign m_axi_wdata = wdch_dout[WID_OFFSET-1:WDATA_OFFSET]; + assign m_axi_wstrb = wdch_dout[WDATA_OFFSET-1:WSTRB_OFFSET]; + assign m_axi_wlast = wdch_dout[0]; + assign wdch_din[WID_OFFSET-1:WDATA_OFFSET] = s_axi_wdata; + assign wdch_din[WDATA_OFFSET-1:WSTRB_OFFSET] = s_axi_wstrb; + assign wdch_din[0] = s_axi_wlast; + end endgenerate // axi_wdch_output + +// generate if ((IS_AXI_FULL_WDCH == 1 || (C_WDCH_TYPE == 1)) ) begin +// assign m_axi_wid = 0; +// end endgenerate + + generate if ((IS_AXI_FULL_WDCH == 1 || (C_WDCH_TYPE == 1))) begin + assign m_axi_wuser = wdch_dout[WSTRB_OFFSET-1:WUSER_OFFSET]; + end endgenerate + + generate if (IS_AXI_FULL_WRCH == 1 || (C_WRCH_TYPE == 1)) begin : axi_wrch_output + assign s_axi_bresp = wrch_dout[BID_OFFSET-1:BRESP_OFFSET]; + assign wrch_din[BID_OFFSET-1:BRESP_OFFSET] = m_axi_bresp; + end endgenerate // axi_wrch_output + + generate if ((IS_AXI_FULL_WRCH == 1 || (C_WRCH_TYPE == 1))) begin : axi_buser + assign s_axi_buser = wrch_dout[BRESP_OFFSET-1:BUSER_OFFSET]; + end endgenerate // axi_buser + + generate if ((IS_AXI_FULL_WRCH == 1 || ( C_WRCH_TYPE == 1))) begin : axi_bid + assign s_axi_bid = wrch_dout[C_DIN_WIDTH_WRCH-1:BID_OFFSET]; + end endgenerate // axi_bid + + + generate if ((IS_AXI_FULL_WACH == 1 || ( C_WACH_TYPE == 1))) begin : gwach_din1 + assign wach_din[AWREGION_OFFSET-1:AWUSER_OFFSET] = s_axi_awuser; + end endgenerate // gwach_din1 + + generate if ((IS_AXI_FULL_WACH == 1 || ( C_WACH_TYPE == 1))) begin : gwach_din2 + assign wach_din[C_DIN_WIDTH_WACH-1:AWID_OFFSET] = s_axi_awid; + end endgenerate // gwach_din2 + + generate if ((IS_AXI_FULL_WACH == 1 || ( C_WACH_TYPE == 1))) begin : gwach_din3 + assign wach_din[AWQOS_OFFSET-1:AWREGION_OFFSET] = s_axi_awregion; + end endgenerate // gwach_din3 + + generate if ((IS_AXI_FULL_WDCH == 1 || ( C_WDCH_TYPE == 1))) begin : gwdch_din1 + assign wdch_din[WSTRB_OFFSET-1:WUSER_OFFSET] = s_axi_wuser; + end endgenerate // gwdch_din1 + + generate if ((IS_AXI_FULL_WRCH == 1 || ( C_WRCH_TYPE == 1))) begin : gwrch_din1 + assign wrch_din[BRESP_OFFSET-1:BUSER_OFFSET] = m_axi_buser; + end endgenerate // gwrch_din1 + + generate if ((IS_AXI_FULL_WRCH == 1 || ( C_WRCH_TYPE == 1))) begin : gwrch_din2 + assign wrch_din[C_DIN_WIDTH_WRCH-1:BID_OFFSET] = m_axi_bid; + end endgenerate // gwrch_din2 + + //end of axi_write_channel + + //########################################################################### + // AXI FULL Read Channel (axi_read_channel) + //########################################################################### + wire [C_DIN_WIDTH_RACH-1:0] rach_din ; + wire [C_DIN_WIDTH_RACH-1:0] rach_dout ; + wire [C_DIN_WIDTH_RACH-1:0] rach_dout_pkt ; + wire rach_full ; + wire rach_almost_full ; + wire rach_prog_full ; + wire rach_empty ; + wire rach_almost_empty ; + wire rach_prog_empty ; + wire [C_DIN_WIDTH_RDCH_ECC-1:0] rdch_din ; + wire [C_DIN_WIDTH_RDCH_ECC-1:0] rdch_dout ; + wire rdch_full ; + wire rdch_almost_full ; + wire rdch_prog_full ; + wire rdch_empty ; + wire rdch_almost_empty ; + wire rdch_prog_empty ; + wire axi_ar_underflow_i ; + wire axi_r_underflow_i ; + wire axi_ar_overflow_i ; + wire axi_r_overflow_i ; + wire rach_s_axi_arready ; + wire rach_m_axi_arvalid ; + wire rach_rd_en ; + wire rdch_m_axi_rready ; + wire rdch_s_axi_rvalid ; + wire rdch_wr_en ; + wire rdch_rd_en ; + wire arvalid_pkt ; + wire arready_pkt ; + wire arvalid_en ; + wire rdch_rd_ok ; + wire accept_next_pkt ; + integer rdch_free_space ; + integer rdch_commited_space ; + wire rach_re ; + wire rdch_we ; + wire rdch_re ; + + localparam ARID_OFFSET = C_DIN_WIDTH_RACH - AXI_ID_WIDTH ; + localparam ARADDR_OFFSET = ARID_OFFSET - AXI_ADDR_WIDTH; + localparam ARLEN_OFFSET = ARADDR_OFFSET - AXI_LEN_WIDTH ; + localparam ARSIZE_OFFSET = ARLEN_OFFSET - C_AXI_SIZE_WIDTH ; + localparam ARBURST_OFFSET = ARSIZE_OFFSET - C_AXI_BURST_WIDTH ; + localparam ARLOCK_OFFSET = ARBURST_OFFSET - C_AXI_LOCK_WIDTH ; + localparam ARCACHE_OFFSET = ARLOCK_OFFSET - C_AXI_CACHE_WIDTH ; + localparam ARPROT_OFFSET = ARCACHE_OFFSET - C_AXI_PROT_WIDTH; + localparam ARQOS_OFFSET = ARPROT_OFFSET - C_AXI_QOS_WIDTH; + localparam ARREGION_OFFSET = ARQOS_OFFSET - C_AXI_REGION_WIDTH ; + localparam ARUSER_OFFSET = ARREGION_OFFSET-AXI_ARUSER_WIDTH; + + localparam RID_OFFSET = C_DIN_WIDTH_RDCH - AXI_ID_WIDTH ; + localparam RDATA_OFFSET = RID_OFFSET - AXI_DATA_WIDTH; + localparam RRESP_OFFSET = RDATA_OFFSET - C_AXI_RRESP_WIDTH; + localparam RUSER_OFFSET = RRESP_OFFSET-AXI_RUSER_WIDTH; + + generate begin : xpm_fifo_rd_chnl + if (IS_RD_ADDR_CH == 1) begin : axi_read_addr_channel + + // Write protection when almost full or prog_full is high + + // Read protection when almost empty or prog_empty is high + assign rach_re = (PACKET_FIFO == "true") ? arready_pkt & arvalid_en : m_axi_arready; + assign rach_rd_en = rach_re; + + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_RACH), + .ECC_MODE (0), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_RACH ), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_RACH), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES ("0101"), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_RACH), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_rach_dut ( + .sleep (1'b0), + .rst (rst_axif_sclk), + .wr_clk (s_aclk), + .wr_en (s_axi_arvalid), + .din (rach_din), + .full (rach_full), + .full_n (), + .prog_full (), + .wr_data_count (), + .overflow (axi_ar_overflow_i), + .wr_rst_busy (wr_rst_busy_rach), + .almost_full (), + .wr_ack (), + .rd_clk (m_aclk_int), + .rd_en (rach_rd_en), + .dout (rach_dout_pkt), + .empty (rach_empty), + .prog_empty (), + .rd_data_count (), + .underflow (axi_ar_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (1'b0), + .injectdbiterr (1'b0), + .sbiterr (), + .dbiterr () + ); + + + assign rach_s_axi_arready = (FIFO_MEMORY_TYPE_RACH == "lutram") ? ~(rach_full | wr_rst_busy_rach) : ~rach_full; + assign rach_m_axi_arvalid = ~rach_empty; + assign s_axi_arready = rach_s_axi_arready; + + + end : axi_read_addr_channel + + + // Register Slice for Read Address Channel for MM Packet FIFO + if (C_RACH_TYPE == 0 && (PACKET_FIFO == "true")) begin : grach_reg_slice_mm_pkt_fifo + + xpm_fifo_axi_reg_slice + #( + .C_DATA_WIDTH (C_DIN_WIDTH_RACH), + .C_REG_CONFIG (1) + ) + reg_slice_mm_pkt_fifo_inst + ( + // System Signals + .ACLK (s_aclk), + .ARESET (rst_axif_sclk), + + // Slave side + .S_PAYLOAD_DATA (rach_dout_pkt), + .S_VALID (arvalid_pkt), + .S_READY (arready_pkt), + + // Master side + .M_PAYLOAD_DATA (rach_dout), + .M_VALID (m_axi_arvalid), + .M_READY (m_axi_arready) + ); + end : grach_reg_slice_mm_pkt_fifo + + + if (C_RACH_TYPE == 0 && (PACKET_FIFO == "false")) begin : grach_m_axi_arvalid + assign m_axi_arvalid = rach_m_axi_arvalid; + assign rach_dout = rach_dout_pkt; + end : grach_m_axi_arvalid + + + if (PACKET_FIFO == "true") begin : axi_mm_pkt_fifo_rd + assign rdch_rd_ok = rdch_s_axi_rvalid && rdch_rd_en; + assign arvalid_pkt = rach_m_axi_arvalid && arvalid_en; + assign accept_next_pkt = rach_m_axi_arvalid && arready_pkt && arvalid_en; + + always@(posedge s_aclk ) begin + if(rst_axif_sclk) begin + rdch_commited_space <= 0; + end else begin + if(rdch_rd_ok && !accept_next_pkt) begin + rdch_commited_space <= rdch_commited_space-1; + end else if(!rdch_rd_ok && accept_next_pkt) begin + rdch_commited_space <= rdch_commited_space+(rach_dout_pkt[ARADDR_OFFSET-1:ARLEN_OFFSET]+1); + end else if(rdch_rd_ok && accept_next_pkt) begin + rdch_commited_space <= rdch_commited_space+(rach_dout_pkt[ARADDR_OFFSET-1:ARLEN_OFFSET]); + end + end + end //Always end + + always@(*) begin + rdch_free_space <= (FIFO_DEPTH_RDCH -(rdch_commited_space+rach_dout_pkt[ARADDR_OFFSET-1:ARLEN_OFFSET]+1)); + end + + assign arvalid_en = (rdch_free_space >= 0)? 1:0; + end : axi_mm_pkt_fifo_rd + + if (PACKET_FIFO == "false") begin : axi_mm_fifo_rd + assign arvalid_en = 1; + end :axi_mm_fifo_rd + + if (IS_RD_DATA_CH == 1) begin : axi_read_data_channel + + // Write protection when almost full or prog_full is high + assign rdch_we = rdch_m_axi_rready & m_axi_rvalid ; + + // Read protection when almost empty or prog_empty is high + assign rdch_re = rdch_s_axi_rvalid & s_axi_rready; + assign rdch_wr_en = rdch_we; + assign rdch_rd_en = rdch_re; + + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_RDCH), + .ECC_MODE (P_ECC_MODE_RDCH ), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_RDCH ), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_RDCH_ECC), + .WR_DATA_COUNT_WIDTH (WR_DATA_COUNT_WIDTH_RDCH), + .PROG_FULL_THRESH (PROG_FULL_THRESH_RDCH ), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES (USE_ADV_FEATURES_RDCH_INT), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_RDCH_ECC), + .RD_DATA_COUNT_WIDTH (RD_DATA_COUNT_WIDTH_RDCH), + .PROG_EMPTY_THRESH (PROG_EMPTY_THRESH_RDCH), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_rdch_dut ( + .sleep (1'b0), + .rst (rst_axif_mclk), + .wr_clk (m_aclk_int), + .wr_en (rdch_wr_en), + .din (rdch_din), + .full (rdch_full), + .full_n (), + .prog_full (prog_full_rdch), + .wr_data_count (wr_data_count_rdch), + .overflow (axi_r_overflow_i), + .wr_rst_busy (wr_rst_busy_rdch), + .almost_full (), + .wr_ack (), + .rd_clk (s_aclk), + .rd_en (rdch_rd_en), + .dout (rdch_dout), + .empty (rdch_empty), + .prog_empty (prog_empty_rdch), + .rd_data_count (rd_data_count_rdch), + .underflow (axi_r_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (injectsbiterr_rdch), + .injectdbiterr (injectdbiterr_rdch), + .sbiterr (sbiterr_rdch), + .dbiterr (dbiterr_rdch) + ); + + assign rdch_s_axi_rvalid = ~rdch_empty; + assign rdch_m_axi_rready = (FIFO_MEMORY_TYPE_RDCH == "lutram") ? ~(rdch_full | wr_rst_busy_rdch) : ~rdch_full; + assign s_axi_rvalid = rdch_s_axi_rvalid; + assign m_axi_rready = rdch_m_axi_rready; + + end :axi_read_data_channel + + + + + + if (IS_AXI_FULL_RACH == 1 || ( C_RACH_TYPE == 1)) begin : axi_full_rach_output + assign m_axi_araddr = rach_dout[ARID_OFFSET-1:ARADDR_OFFSET]; + assign m_axi_arlen = rach_dout[ARADDR_OFFSET-1:ARLEN_OFFSET]; + assign m_axi_arsize = rach_dout[ARLEN_OFFSET-1:ARSIZE_OFFSET]; + assign m_axi_arburst = rach_dout[ARSIZE_OFFSET-1:ARBURST_OFFSET]; + assign m_axi_arlock = rach_dout[ARBURST_OFFSET-1:ARLOCK_OFFSET]; + assign m_axi_arcache = rach_dout[ARLOCK_OFFSET-1:ARCACHE_OFFSET]; + assign m_axi_arprot = rach_dout[ARCACHE_OFFSET-1:ARPROT_OFFSET]; + assign m_axi_arqos = rach_dout[ARPROT_OFFSET-1:ARQOS_OFFSET]; + assign rach_din[ARID_OFFSET-1:ARADDR_OFFSET] = s_axi_araddr; + assign rach_din[ARADDR_OFFSET-1:ARLEN_OFFSET] = s_axi_arlen; + assign rach_din[ARLEN_OFFSET-1:ARSIZE_OFFSET] = s_axi_arsize; + assign rach_din[ARSIZE_OFFSET-1:ARBURST_OFFSET] = s_axi_arburst; + assign rach_din[ARBURST_OFFSET-1:ARLOCK_OFFSET] = s_axi_arlock; + assign rach_din[ARLOCK_OFFSET-1:ARCACHE_OFFSET] = s_axi_arcache; + assign rach_din[ARCACHE_OFFSET-1:ARPROT_OFFSET] = s_axi_arprot; + assign rach_din[ARPROT_OFFSET-1:ARQOS_OFFSET] = s_axi_arqos; + end : axi_full_rach_output + + if ((IS_AXI_FULL_RACH == 1 || ( C_RACH_TYPE == 1))) begin : axi_arregion + assign m_axi_arregion = rach_dout[ARQOS_OFFSET-1:ARREGION_OFFSET]; + end : axi_arregion + + if ((IS_AXI_FULL_RACH == 1 || ( C_RACH_TYPE == 1))) begin : axi_aruser + assign m_axi_aruser = rach_dout[ARREGION_OFFSET-1:ARUSER_OFFSET]; + end : axi_aruser + + if ((IS_AXI_FULL_RACH == 1 || ( C_RACH_TYPE == 1))) begin : axi_arid + assign m_axi_arid = rach_dout[C_DIN_WIDTH_RACH-1:ARID_OFFSET]; + end : axi_arid + + if (IS_AXI_FULL_RDCH == 1 || ( C_RDCH_TYPE == 1)) begin : axi_full_rdch_output + assign s_axi_rdata = rdch_dout[RID_OFFSET-1:RDATA_OFFSET]; + assign s_axi_rresp = rdch_dout[RDATA_OFFSET-1:RRESP_OFFSET]; + assign s_axi_rlast = rdch_dout[0]; + assign rdch_din[RID_OFFSET-1:RDATA_OFFSET] = m_axi_rdata; + assign rdch_din[RDATA_OFFSET-1:RRESP_OFFSET] = m_axi_rresp; + assign rdch_din[0] = m_axi_rlast; + end : axi_full_rdch_output + + if ((IS_AXI_FULL_RDCH == 1 || ( C_RDCH_TYPE == 1))) begin : axi_full_ruser_output + assign s_axi_ruser = rdch_dout[RRESP_OFFSET-1:RUSER_OFFSET]; + end : axi_full_ruser_output + + if ((IS_AXI_FULL_RDCH == 1 || ( C_RDCH_TYPE == 1))) begin : axi_rid + assign s_axi_rid = rdch_dout[C_DIN_WIDTH_RDCH-1:RID_OFFSET]; + end : axi_rid + + + if ((IS_AXI_FULL_RACH == 1 || ( C_RACH_TYPE == 1))) begin : grach_din1 + assign rach_din[ARREGION_OFFSET-1:ARUSER_OFFSET] = s_axi_aruser; + end : grach_din1 + + if ((IS_AXI_FULL_RACH == 1 || ( C_RACH_TYPE == 1))) begin : grach_din2 + assign rach_din[C_DIN_WIDTH_RACH-1:ARID_OFFSET] = s_axi_arid; + end : grach_din2 + + if ((IS_AXI_FULL_RACH == 1 || ( C_RACH_TYPE == 1))) begin + assign rach_din[ARQOS_OFFSET-1:ARREGION_OFFSET] = s_axi_arregion; + end + + if ((IS_AXI_FULL_RDCH == 1 || ( C_RDCH_TYPE == 1))) begin : grdch_din1 + assign rdch_din[RRESP_OFFSET-1:RUSER_OFFSET] = m_axi_ruser; + end : grdch_din1 + + if ((IS_AXI_FULL_RDCH == 1 || ( C_RDCH_TYPE == 1))) begin : grdch_din2 + assign rdch_din[C_DIN_WIDTH_RDCH-1:RID_OFFSET] = m_axi_rid; + end : grdch_din2 + + //end of axi_read_channel + + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + // Pass Through Logic or Wiring Logic + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // Pass Through Logic for Read Channel + //------------------------------------------------------------------------- + + // Wiring logic for Write Address Channel + if (C_WACH_TYPE == 2) begin : gwach_pass_through + assign m_axi_awid = s_axi_awid; + assign m_axi_awaddr = s_axi_awaddr; + assign m_axi_awlen = s_axi_awlen; + assign m_axi_awsize = s_axi_awsize; + assign m_axi_awburst = s_axi_awburst; + assign m_axi_awlock = s_axi_awlock; + assign m_axi_awcache = s_axi_awcache; + assign m_axi_awprot = s_axi_awprot; + assign m_axi_awqos = s_axi_awqos; + assign m_axi_awregion = s_axi_awregion; + assign m_axi_awuser = s_axi_awuser; + assign s_axi_awready = m_axi_awready; + assign m_axi_awvalid = s_axi_awvalid; + end //: gwach_pass_through; + + // Wiring logic for Write Data Channel + if (C_WDCH_TYPE == 2) begin : gwdch_pass_through +// assign m_axi_wid = s_axi_wid; + assign m_axi_wdata = s_axi_wdata; + assign m_axi_wstrb = s_axi_wstrb; + assign m_axi_wlast = s_axi_wlast; + assign m_axi_wuser = s_axi_wuser; + assign s_axi_wready = m_axi_wready; + assign m_axi_wvalid = s_axi_wvalid; + end //: gwdch_pass_through; + + // Wiring logic for Write Response Channel + if (C_WRCH_TYPE == 2) begin : gwrch_pass_through + assign s_axi_bid = m_axi_bid; + assign s_axi_bresp = m_axi_bresp; + assign s_axi_buser = m_axi_buser; + assign m_axi_bready = s_axi_bready; + assign s_axi_bvalid = m_axi_bvalid; + end //: gwrch_pass_through; + + //------------------------------------------------------------------------- + // Pass Through Logic for Read Channel + //------------------------------------------------------------------------- + + // Wiring logic for Read Address Channel + if (C_RACH_TYPE == 2) begin : grach_pass_through + assign m_axi_arid = s_axi_arid; + assign m_axi_araddr = s_axi_araddr; + assign m_axi_arlen = s_axi_arlen; + assign m_axi_arsize = s_axi_arsize; + assign m_axi_arburst = s_axi_arburst; + assign m_axi_arlock = s_axi_arlock; + assign m_axi_arcache = s_axi_arcache; + assign m_axi_arprot = s_axi_arprot; + assign m_axi_arqos = s_axi_arqos; + assign m_axi_arregion = s_axi_arregion; + assign m_axi_aruser = s_axi_aruser; + assign s_axi_arready = m_axi_arready; + assign m_axi_arvalid = s_axi_arvalid; + end //: grach_pass_through; + + // Wiring logic for Read Data Channel + if (C_RDCH_TYPE == 2) begin : grdch_pass_through + assign s_axi_rid = m_axi_rid; + assign s_axi_rlast = m_axi_rlast; + assign s_axi_ruser = m_axi_ruser; + assign s_axi_rdata = m_axi_rdata; + assign s_axi_rresp = m_axi_rresp; + assign s_axi_rvalid = m_axi_rvalid; + assign m_axi_rready = s_axi_rready; + end //: grdch_pass_through; + +end : xpm_fifo_rd_chnl +endgenerate + + +endmodule //xpm_fifo_axif + + +/******************************************************************************* + * Declaration of top-level module + ******************************************************************************/ +(* XPM_MODULE = "TRUE", KEEP_HIERARCHY = "SOFT" *) +module xpm_fifo_axil + #( + //----------------------------------------------------------------------- + // Generic Declarations + //----------------------------------------------------------------------- + parameter integer AXI_ADDR_WIDTH = 32, + parameter integer AXI_DATA_WIDTH = 32, + parameter CLOCKING_MODE = "common", + parameter integer SIM_ASSERT_CHK = 0, + parameter integer CASCADE_HEIGHT = 0, + parameter integer CDC_SYNC_STAGES = 2, + parameter integer EN_RESET_SYNCHRONIZER = 0, + parameter FIFO_MEMORY_TYPE_WACH = "lutram", + parameter FIFO_MEMORY_TYPE_WDCH = "bram", + parameter FIFO_MEMORY_TYPE_WRCH = "lutram", + parameter FIFO_MEMORY_TYPE_RACH = "lutram", + parameter FIFO_MEMORY_TYPE_RDCH = "bram", + parameter integer FIFO_DEPTH_WACH = 16, + parameter integer FIFO_DEPTH_WDCH = 16, + parameter integer FIFO_DEPTH_WRCH = 2048, + parameter integer FIFO_DEPTH_RACH = 16, + parameter integer FIFO_DEPTH_RDCH = 2048, + parameter ECC_MODE_WDCH = "no_ecc", + parameter ECC_MODE_RDCH = "no_ecc", + parameter USE_ADV_FEATURES_WDCH = "1000", + parameter USE_ADV_FEATURES_RDCH = "1000", + parameter integer WR_DATA_COUNT_WIDTH_WDCH = 10, + parameter integer WR_DATA_COUNT_WIDTH_RDCH = 10, + parameter integer RD_DATA_COUNT_WIDTH_WDCH = 10, + parameter integer RD_DATA_COUNT_WIDTH_RDCH = 10, + parameter integer PROG_FULL_THRESH_WDCH = 10, + parameter integer PROG_FULL_THRESH_RDCH = 10, + parameter integer PROG_EMPTY_THRESH_WDCH = 10, + parameter integer PROG_EMPTY_THRESH_RDCH = 10 + + + ) + + ( + // AXI Global Signal + input wire m_aclk, + input wire s_aclk, + input wire s_aresetn, + + // AXI Full/Lite Slave Write Channel (write side) + input wire [AXI_ADDR_WIDTH-1:0] s_axi_awaddr, + input wire [3-1:0] s_axi_awprot, + input wire s_axi_awvalid, + output wire s_axi_awready, + input wire [AXI_DATA_WIDTH-1:0] s_axi_wdata, + input wire [AXI_DATA_WIDTH/8-1:0] s_axi_wstrb, + input wire s_axi_wvalid, + output wire s_axi_wready, + output wire [2-1:0] s_axi_bresp, + output wire s_axi_bvalid, + input wire s_axi_bready, + + // AXI Full/Lite Master Write Channel (read side) + output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr, + output wire [3-1:0] m_axi_awprot, + output wire m_axi_awvalid, + input wire m_axi_awready, + output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata, + output wire [AXI_DATA_WIDTH/8-1:0] m_axi_wstrb, + output wire m_axi_wvalid, + input wire m_axi_wready, + input wire [2-1:0] m_axi_bresp, + input wire m_axi_bvalid, + output wire m_axi_bready, + + // AXI Full/Lite Slave Read Channel (write side) + input wire [AXI_ADDR_WIDTH-1:0] s_axi_araddr, + input wire [3-1:0] s_axi_arprot, + input wire s_axi_arvalid, + output wire s_axi_arready, + output wire [AXI_DATA_WIDTH-1:0] s_axi_rdata, + output wire [2-1:0] s_axi_rresp, + output wire s_axi_rvalid, + input wire s_axi_rready, + + // AXI Full/Lite Master Read Channel (read side) + output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr, + output wire [3-1:0] m_axi_arprot, + output wire m_axi_arvalid, + input wire m_axi_arready, + input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata, + input wire [2-1:0] m_axi_rresp, + input wire m_axi_rvalid, + output wire m_axi_rready, + + // AXI4-Full Sideband Signals + output wire prog_full_wdch, + output wire prog_empty_wdch, + output wire [WR_DATA_COUNT_WIDTH_WDCH-1:0] wr_data_count_wdch, + output wire [RD_DATA_COUNT_WIDTH_WDCH-1:0] rd_data_count_wdch, + output wire prog_full_rdch, + output wire prog_empty_rdch, + output wire [WR_DATA_COUNT_WIDTH_RDCH-1:0] wr_data_count_rdch, + output wire [RD_DATA_COUNT_WIDTH_RDCH-1:0] rd_data_count_rdch, + + // ECC Related ports + input wire injectsbiterr_wdch, + input wire injectdbiterr_wdch, + output wire sbiterr_wdch, + output wire dbiterr_wdch, + input wire injectsbiterr_rdch, + input wire injectdbiterr_rdch, + output wire sbiterr_rdch, + output wire dbiterr_rdch + + ); + + + + // Function to convert ASCII value to binary + function [3:0] str2bin; + input [7:0] str_val_ascii; + if((str_val_ascii == 8'h30) || (str_val_ascii == 8'h31) || + (str_val_ascii == 8'h32) || (str_val_ascii == 8'h33) || + (str_val_ascii == 8'h34) || (str_val_ascii == 8'h35) || + (str_val_ascii == 8'h36) || (str_val_ascii == 8'h37) || + (str_val_ascii == 8'h38) || (str_val_ascii == 8'h39) || + (str_val_ascii == 8'h41) || (str_val_ascii == 8'h42) || + (str_val_ascii == 8'h43) || (str_val_ascii == 8'h44) || + (str_val_ascii == 8'h45) || (str_val_ascii == 8'h46) || + (str_val_ascii == 8'h61) || (str_val_ascii == 8'h62) || + (str_val_ascii == 8'h63) || (str_val_ascii == 8'h64) || + (str_val_ascii == 8'h65) || (str_val_ascii == 8'h66) || + (str_val_ascii == 8'h00)) begin + if (!str_val_ascii[6]) + str2bin = str_val_ascii[3:0]; + else begin + str2bin [3] = 1'b1; + str2bin [2] = str_val_ascii[2] | (str_val_ascii[1] & str_val_ascii[0]); + str2bin [1] = str_val_ascii[0] ^ str_val_ascii[1]; + str2bin [0] = !str_val_ascii[0]; + end + end + else + $error("Found Invalid character while parsing the string, please cross check the value specified for either READ_RESET_VALUE_A|B or MEMORY_INIT_PARAM (if initialization of memory through parameter is used). XPM_MEMORY supports strings (hex) that contains characters 0-9, A-F and a-f."); + endfunction + // Function that parses the complete reset value string + function logic [15:0] hstr2bin; + input [16*8-1 : 0] hstr_val; + integer rst_loop_a; + localparam integer rsta_loop_iter = 16; + logic [rsta_loop_iter-1 : 0] rst_val_conv_a_i; + for (rst_loop_a=1; rst_loop_a <= rsta_loop_iter/4; rst_loop_a = rst_loop_a+1) begin + rst_val_conv_a_i[(rst_loop_a*4)-1 -: 4] = str2bin(hstr_val[(rst_loop_a*8)-1 -: 8]); + end + return rst_val_conv_a_i[15:0]; + endfunction + +//Function to convert binary to ASCII value + function [7:0] bin2str; + input [3:0] bin_val; + if( bin_val > 4'h9) begin + bin2str [7:4] = 4'h4; + bin2str [3] = 1'b0; + bin2str [2:0] = bin_val[2:0]-1'b1; + end + else begin + bin2str [7:4] = 4'h3; + bin2str [3:0] = bin_val; + end + endfunction + + // Function that parses the complete binary value to string + function [31:0] bin2hstr; + input [15 : 0] bin_val; + integer str_pos; + localparam integer str_max_bits = 32; + for (str_pos=1; str_pos <= str_max_bits/8; str_pos = str_pos+1) begin + bin2hstr[(str_pos*8)-1 -: 8] = bin2str(bin_val[(str_pos*4)-1 -: 4]); + end + endfunction + +//WDCH advanced features parameter conversion + localparam [15:0] EN_ADV_FEATURE_WDCH = hstr2bin(USE_ADV_FEATURES_WDCH); + localparam EN_DATA_VALID_INT = 1'b1; + localparam [15:0] EN_ADV_FEATURE_WDCH_INT = {EN_ADV_FEATURE_WDCH[15:13], EN_DATA_VALID_INT, EN_ADV_FEATURE_WDCH[11:0]}; + localparam USE_ADV_FEATURES_WDCH_INT = bin2hstr(EN_ADV_FEATURE_WDCH_INT); + + +//RDCH advanced features parameter conversion + localparam [15:0] EN_ADV_FEATURE_RDCH = hstr2bin(USE_ADV_FEATURES_RDCH); + localparam [15:0] EN_ADV_FEATURE_RDCH_INT = {EN_ADV_FEATURE_RDCH[15:13], EN_DATA_VALID_INT, EN_ADV_FEATURE_RDCH[11:0]}; + localparam USE_ADV_FEATURES_RDCH_INT = bin2hstr(EN_ADV_FEATURE_RDCH_INT); + + + localparam C_WACH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logic + localparam C_WDCH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logie + localparam C_WRCH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logie + localparam C_RACH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logie + localparam C_RDCH_TYPE = 0; // 0 = FIFO, 1 = Register Slice, 2 = Pass Through Logie + + // Input Data Width + // Accumulation of all AXI input signal's width + localparam C_DIN_WIDTH_WACH = AXI_ADDR_WIDTH+3; + localparam C_DIN_WIDTH_WDCH = AXI_DATA_WIDTH/8+AXI_DATA_WIDTH; + localparam C_DIN_WIDTH_WRCH = 2; + localparam C_DIN_WIDTH_RACH = AXI_ADDR_WIDTH+3; + localparam C_DIN_WIDTH_RDCH = AXI_DATA_WIDTH+2; + + + // Define local parameters for mapping with base file + localparam integer P_COMMON_CLOCK = ( (CLOCKING_MODE == "common_clock" || CLOCKING_MODE == "COMMON_CLOCK" || CLOCKING_MODE == "COMMON" || CLOCKING_MODE == "common") ? 1 : + ( (CLOCKING_MODE == "independent_clock" || CLOCKING_MODE == "INDEPENDENT_CLOCK" || CLOCKING_MODE == "INDEPENDENT" || CLOCKING_MODE == "independent") ? 0 : 2)); + + localparam integer P_ECC_MODE_WDCH = ( (ECC_MODE_WDCH == "no_ecc" || ECC_MODE_WDCH == "NO_ECC" ) ? 0 : 1); + localparam integer P_ECC_MODE_RDCH = ( (ECC_MODE_RDCH == "no_ecc" || ECC_MODE_RDCH == "NO_ECC" ) ? 0 : 1); + localparam integer P_FIFO_MEMORY_TYPE_WACH = ( (FIFO_MEMORY_TYPE_WACH == "lutram" || FIFO_MEMORY_TYPE_WACH == "LUTRAM" || FIFO_MEMORY_TYPE_WACH == "distributed" || FIFO_MEMORY_TYPE_WACH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_WACH == "blockram" || FIFO_MEMORY_TYPE_WACH == "BLOCKRAM" || FIFO_MEMORY_TYPE_WACH == "bram" || FIFO_MEMORY_TYPE_WACH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_WACH == "ultraram" || FIFO_MEMORY_TYPE_WACH == "ULTRARAM" || FIFO_MEMORY_TYPE_WACH == "uram" || FIFO_MEMORY_TYPE_WACH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_WACH == "builtin" || FIFO_MEMORY_TYPE_WACH == "BUILTIN") ? 4 : 0)))); + localparam integer P_FIFO_MEMORY_TYPE_WDCH = ( (FIFO_MEMORY_TYPE_WDCH == "lutram" || FIFO_MEMORY_TYPE_WDCH == "LUTRAM" || FIFO_MEMORY_TYPE_WDCH == "distributed" || FIFO_MEMORY_TYPE_WDCH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_WDCH == "blockram" || FIFO_MEMORY_TYPE_WDCH == "BLOCKRAM" || FIFO_MEMORY_TYPE_WDCH == "bram" || FIFO_MEMORY_TYPE_WDCH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_WDCH == "ultraram" || FIFO_MEMORY_TYPE_WDCH == "ULTRARAM" || FIFO_MEMORY_TYPE_WDCH == "uram" || FIFO_MEMORY_TYPE_WDCH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_WDCH == "builtin" || FIFO_MEMORY_TYPE_WDCH == "BUILTIN") ? 4 : 0)))); + localparam integer P_FIFO_MEMORY_TYPE_WRCH = ( (FIFO_MEMORY_TYPE_WRCH == "lutram" || FIFO_MEMORY_TYPE_WRCH == "LUTRAM" || FIFO_MEMORY_TYPE_WRCH == "distributed" || FIFO_MEMORY_TYPE_WRCH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_WRCH == "blockram" || FIFO_MEMORY_TYPE_WRCH == "BLOCKRAM" || FIFO_MEMORY_TYPE_WRCH == "bram" || FIFO_MEMORY_TYPE_WRCH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_WRCH == "ultraram" || FIFO_MEMORY_TYPE_WRCH == "ULTRARAM" || FIFO_MEMORY_TYPE_WRCH == "uram" || FIFO_MEMORY_TYPE_WRCH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_WRCH == "builtin" || FIFO_MEMORY_TYPE_WRCH == "BUILTIN") ? 4 : 0)))); + localparam integer P_FIFO_MEMORY_TYPE_RACH = ( (FIFO_MEMORY_TYPE_RACH == "lutram" || FIFO_MEMORY_TYPE_RACH == "LUTRAM" || FIFO_MEMORY_TYPE_RACH == "distributed" || FIFO_MEMORY_TYPE_RACH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_RACH == "blockram" || FIFO_MEMORY_TYPE_RACH == "BLOCKRAM" || FIFO_MEMORY_TYPE_RACH == "bram" || FIFO_MEMORY_TYPE_RACH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_RACH == "ultraram" || FIFO_MEMORY_TYPE_RACH == "ULTRARAM" || FIFO_MEMORY_TYPE_RACH == "uram" || FIFO_MEMORY_TYPE_RACH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_RACH == "builtin" || FIFO_MEMORY_TYPE_RACH == "BUILTIN") ? 4 : 0)))); + localparam integer P_FIFO_MEMORY_TYPE_RDCH = ( (FIFO_MEMORY_TYPE_RDCH == "lutram" || FIFO_MEMORY_TYPE_RDCH == "LUTRAM" || FIFO_MEMORY_TYPE_RDCH == "distributed" || FIFO_MEMORY_TYPE_RDCH == "DISTRIBUTED") ? 1 : + ( (FIFO_MEMORY_TYPE_RDCH == "blockram" || FIFO_MEMORY_TYPE_RDCH == "BLOCKRAM" || FIFO_MEMORY_TYPE_RDCH == "bram" || FIFO_MEMORY_TYPE_RDCH == "BRAM") ? 2 : + ( (FIFO_MEMORY_TYPE_RDCH == "ultraram" || FIFO_MEMORY_TYPE_RDCH == "ULTRARAM" || FIFO_MEMORY_TYPE_RDCH == "uram" || FIFO_MEMORY_TYPE_RDCH == "URAM") ? 3 : + ( (FIFO_MEMORY_TYPE_RDCH == "builtin" || FIFO_MEMORY_TYPE_RDCH == "BUILTIN") ? 4 : 0)))); + + localparam C_DIN_WIDTH_WDCH_ECC = (P_ECC_MODE_WDCH == 0) ? C_DIN_WIDTH_WDCH : ((C_DIN_WIDTH_WDCH%64 == 0) ? C_DIN_WIDTH_WDCH : (64*(C_DIN_WIDTH_WDCH/64+1))); + localparam C_DIN_WIDTH_RDCH_ECC = (P_ECC_MODE_RDCH == 0) ? C_DIN_WIDTH_RDCH : ((C_DIN_WIDTH_RDCH%64 == 0) ? C_DIN_WIDTH_RDCH : (64*(C_DIN_WIDTH_RDCH/64+1))); + + + + wire wr_rst_busy_wach; + wire wr_rst_busy_wdch; + wire wr_rst_busy_wrch; + wire wr_rst_busy_rach; + wire wr_rst_busy_rdch; + + + + localparam C_AXI_PROT_WIDTH = 3; + localparam C_AXI_BRESP_WIDTH = 2; + localparam C_AXI_RRESP_WIDTH = 2; + + + wire inverted_reset = ~s_aresetn; + wire rst_axil_sclk; + wire rst_axil_mclk; + wire m_aclk_int; + assign m_aclk_int = P_COMMON_CLOCK ? s_aclk : m_aclk; + + generate + if (EN_RESET_SYNCHRONIZER == 1) begin : gen_sync_reset +//Reset Synchronizer + xpm_cdc_sync_rst #( + .DEST_SYNC_FF (P_COMMON_CLOCK ? 4 : CDC_SYNC_STAGES), + .INIT (0), + .INIT_SYNC_FF (1), + .SIM_ASSERT_CHK (0) + ) xpm_cdc_sync_rst_sclk_inst ( + .src_rst (~s_aresetn), + .dest_clk (s_aclk), + .dest_rst (rst_axil_sclk) + ); + xpm_cdc_sync_rst #( + .DEST_SYNC_FF (P_COMMON_CLOCK ? 4 : CDC_SYNC_STAGES), + .INIT (0), + .INIT_SYNC_FF (1), + .SIM_ASSERT_CHK (0) + ) xpm_cdc_sync_rst_mclk_inst ( + .src_rst (~s_aresetn), + .dest_clk (m_aclk_int), + .dest_rst (rst_axil_mclk) + ); + end // gen_sync_reset + if (EN_RESET_SYNCHRONIZER == 0) begin : gen_async_reset + assign rst_axil_sclk = inverted_reset; + assign rst_axil_mclk = inverted_reset; + + end // gen_async_reset + endgenerate + + //########################################################################### + // AXI FULL Write Channel (axi_write_channel) + //########################################################################### + + + + localparam IS_AXI_LITE_WACH = ((C_WACH_TYPE == 0)) ? 1 : 0; + localparam IS_AXI_LITE_WDCH = ((C_WDCH_TYPE == 0)) ? 1 : 0; + localparam IS_AXI_LITE_WRCH = ((C_WRCH_TYPE == 0)) ? 1 : 0; + localparam IS_AXI_LITE_RACH = ((C_RACH_TYPE == 0)) ? 1 : 0; + localparam IS_AXI_LITE_RDCH = ((C_RDCH_TYPE == 0)) ? 1 : 0; + + localparam IS_WR_ADDR_CH = ((IS_AXI_LITE_WACH == 1)) ? 1 : 0; + localparam IS_WR_DATA_CH = ((IS_AXI_LITE_WDCH == 1)) ? 1 : 0; + localparam IS_WR_RESP_CH = ((IS_AXI_LITE_WRCH == 1)) ? 1 : 0; + localparam IS_RD_ADDR_CH = ((IS_AXI_LITE_RACH == 1)) ? 1 : 0; + localparam IS_RD_DATA_CH = ((IS_AXI_LITE_RDCH == 1)) ? 1 : 0; + + localparam AWADDR_OFFSET = C_DIN_WIDTH_WACH - AXI_ADDR_WIDTH; + localparam AWPROT_OFFSET = AWADDR_OFFSET - C_AXI_PROT_WIDTH; + + localparam WDATA_OFFSET = C_DIN_WIDTH_WDCH - AXI_DATA_WIDTH; + localparam WSTRB_OFFSET = WDATA_OFFSET - AXI_DATA_WIDTH/8; + + localparam BRESP_OFFSET = C_DIN_WIDTH_WRCH - C_AXI_BRESP_WIDTH; + + + wire [C_DIN_WIDTH_WACH-1:0] wach_din ; + wire [C_DIN_WIDTH_WACH-1:0] wach_dout ; + wire [C_DIN_WIDTH_WACH-1:0] wach_dout_pkt ; + wire wach_full ; + wire wach_almost_full ; + wire wach_prog_full ; + wire wach_empty ; + wire wach_almost_empty ; + wire wach_prog_empty ; + wire [C_DIN_WIDTH_WDCH_ECC-1:0] wdch_din ; + wire [C_DIN_WIDTH_WDCH_ECC-1:0] wdch_dout ; + wire wdch_full ; + wire wdch_almost_full ; + wire wdch_prog_full ; + wire wdch_empty ; + wire wdch_almost_empty ; + wire wdch_prog_empty ; + wire [C_DIN_WIDTH_WRCH-1:0] wrch_din ; + wire [C_DIN_WIDTH_WRCH-1:0] wrch_dout ; + wire wrch_full ; + wire wrch_almost_full ; + wire wrch_prog_full ; + wire wrch_empty ; + wire wrch_almost_empty ; + wire wrch_prog_empty ; + wire axi_aw_underflow_i; + wire axi_w_underflow_i ; + wire axi_b_underflow_i ; + wire axi_aw_overflow_i ; + wire axi_w_overflow_i ; + wire axi_b_overflow_i ; + wire wach_s_axi_awready; + wire wach_m_axi_awvalid; + wire wach_rd_en ; + wire wdch_s_axi_wready ; + wire wdch_m_axi_wvalid ; + wire wdch_wr_en ; + wire wdch_rd_en ; + wire wrch_s_axi_bvalid ; + wire wrch_m_axi_bready ; + wire txn_count_up ; + wire txn_count_down ; + wire awvalid_en ; + wire awvalid_pkt ; + wire awready_pkt ; + integer wr_pkt_count ; + wire wach_re ; + wire wdch_we ; + wire wdch_re ; + + generate if (IS_WR_ADDR_CH == 1) begin : axi_write_address_channel + // Write protection when almost full or prog_full is high + + // Read protection when almost empty or prog_empty is high + assign wach_re = m_axi_awready; + assign wach_rd_en = wach_re; + + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_WACH), + .ECC_MODE (0), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_WACH ), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_WACH ), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES ("0101"), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_WACH ), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_wach_dut ( + .sleep (1'b0), + .rst (rst_axil_sclk), + .wr_clk (s_aclk), + .wr_en (s_axi_awvalid), + .din (wach_din), + .full (wach_full), + .full_n (), + .prog_full (), + .wr_data_count (), + .overflow (axi_aw_overflow_i), + .wr_rst_busy (wr_rst_busy_wach), + .almost_full (), + .wr_ack (), + .rd_clk (m_aclk_int), + .rd_en (wach_rd_en), + .dout (wach_dout_pkt), + .empty (wach_empty), + .prog_empty (), + .rd_data_count (), + .underflow (axi_aw_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (1'b0), + .injectdbiterr (1'b0), + .sbiterr (), + .dbiterr () + ); + + assign wach_s_axi_awready = (FIFO_MEMORY_TYPE_WACH == "lutram") ? ~(wach_full | wr_rst_busy_wach) : ~wach_full; + assign wach_m_axi_awvalid = ~wach_empty; + assign s_axi_awready = wach_s_axi_awready; + + + end endgenerate // axi_write_address_channel + + assign awvalid_en = 1; + assign wach_dout = wach_dout_pkt; + assign m_axi_awvalid = wach_m_axi_awvalid; + + generate if (IS_WR_DATA_CH == 1) begin : axi_write_data_channel + // Write protection when almost full or prog_full is high + assign wdch_we = wdch_s_axi_wready & s_axi_wvalid ; + + // Read protection when almost empty or prog_empty is high + assign wdch_re = wdch_m_axi_wvalid & m_axi_wready ; + assign wdch_wr_en = wdch_we; + assign wdch_rd_en = wdch_re; + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_WDCH), + .ECC_MODE (P_ECC_MODE_WDCH), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_WDCH), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_WDCH_ECC), + .WR_DATA_COUNT_WIDTH (WR_DATA_COUNT_WIDTH_WDCH), + .PROG_FULL_THRESH (PROG_FULL_THRESH_WDCH), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES (USE_ADV_FEATURES_WDCH_INT), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_WDCH_ECC), + .RD_DATA_COUNT_WIDTH (RD_DATA_COUNT_WIDTH_WDCH), + .PROG_EMPTY_THRESH (PROG_EMPTY_THRESH_WDCH), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_wdch_dut ( + .sleep (1'b0), + .rst (rst_axil_sclk), + .wr_clk (s_aclk), + .wr_en (wdch_wr_en), + .din (wdch_din), + .full (wdch_full), + .full_n (), + .prog_full (prog_full_wdch), + .wr_data_count (wr_data_count_wdch), + .overflow (axi_w_overflow_i), + .wr_rst_busy (wr_rst_busy_wdch), + .almost_full (), + .wr_ack (), + .rd_clk (m_aclk_int), + .rd_en (wdch_rd_en), + .dout (wdch_dout), + .empty (wdch_empty), + .prog_empty (prog_empty_wdch), + .rd_data_count (rd_data_count_wdch), + .underflow (axi_w_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (injectsbiterr_wdch), + .injectdbiterr (injectdbiterr_wdch), + .sbiterr (sbiterr_wdch), + .dbiterr (dbiterr_wdch) + ); + + + assign wdch_s_axi_wready = (FIFO_MEMORY_TYPE_WDCH == "lutram") ? ~(wdch_full | wr_rst_busy_wdch) : ~wdch_full; + assign wdch_m_axi_wvalid = ~wdch_empty; + assign s_axi_wready = wdch_s_axi_wready; + assign m_axi_wvalid = wdch_m_axi_wvalid; + + end endgenerate // axi_write_data_channel + + + generate if (IS_WR_RESP_CH == 1) begin : axi_write_resp_channel + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_WRCH), + .ECC_MODE (0), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_WRCH ), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_WRCH), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES ("0101"), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_WRCH), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_wrch_dut ( + .sleep (1'b0), + .rst (rst_axil_mclk), + .wr_clk (m_aclk_int), + .wr_en (m_axi_bvalid), + .din (wrch_din), + .full (wrch_full), + .full_n (), + .prog_full (), + .wr_data_count (), + .overflow (axi_b_overflow_i), + .wr_rst_busy (wr_rst_busy_wrch), + .almost_full (), + .wr_ack (), + .rd_clk (s_aclk), + .rd_en (s_axi_bready), + .dout (wrch_dout), + .empty (wrch_empty), + .prog_empty (), + .rd_data_count (), + .underflow (axi_b_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (1'b0), + .injectdbiterr (1'b0), + .sbiterr (), + .dbiterr () + ); + + assign wrch_s_axi_bvalid = ~wrch_empty; + assign wrch_m_axi_bready = (FIFO_MEMORY_TYPE_WRCH == "lutram") ? ~(wrch_full | wr_rst_busy_wrch) : ~wrch_full; + assign s_axi_bvalid = wrch_s_axi_bvalid; + assign m_axi_bready = wrch_m_axi_bready; + + end endgenerate // axi_write_resp_channel + + + + generate if (IS_AXI_LITE_WACH == 1 || (C_WACH_TYPE == 1)) begin : axi_wach_output1 + assign wach_din = {s_axi_awaddr, s_axi_awprot}; + assign m_axi_awaddr = wach_dout[C_DIN_WIDTH_WACH-1:AWADDR_OFFSET]; + assign m_axi_awprot = wach_dout[AWADDR_OFFSET-1:AWPROT_OFFSET]; + end endgenerate // axi_wach_output1 + + generate if (IS_AXI_LITE_WDCH == 1 || (C_WDCH_TYPE == 1)) begin : axi_wdch_output1 + assign wdch_din = {s_axi_wdata, s_axi_wstrb}; + assign m_axi_wdata = wdch_dout[C_DIN_WIDTH_WDCH-1:WDATA_OFFSET]; + assign m_axi_wstrb = wdch_dout[WDATA_OFFSET-1:WSTRB_OFFSET]; + end endgenerate // axi_wdch_output1 + + generate if (IS_AXI_LITE_WRCH == 1 || (C_WRCH_TYPE == 1)) begin : axi_wrch_output1 + assign wrch_din = m_axi_bresp; + assign s_axi_bresp = wrch_dout[C_DIN_WIDTH_WRCH-1:BRESP_OFFSET]; + end endgenerate // axi_wrch_output1 + + + //end of axi_write_channel + + //########################################################################### + // AXI FULL Read Channel (axi_read_channel) + //########################################################################### + wire [C_DIN_WIDTH_RACH-1:0] rach_din ; + wire [C_DIN_WIDTH_RACH-1:0] rach_dout ; + wire [C_DIN_WIDTH_RACH-1:0] rach_dout_pkt ; + wire rach_full ; + wire rach_almost_full ; + wire rach_prog_full ; + wire rach_empty ; + wire rach_almost_empty ; + wire rach_prog_empty ; + wire [C_DIN_WIDTH_RDCH_ECC-1:0] rdch_din ; + wire [C_DIN_WIDTH_RDCH_ECC-1:0] rdch_dout ; + wire rdch_full ; + wire rdch_almost_full ; + wire rdch_prog_full ; + wire rdch_empty ; + wire rdch_almost_empty ; + wire rdch_prog_empty ; + wire axi_ar_underflow_i ; + wire axi_r_underflow_i ; + wire axi_ar_overflow_i ; + wire axi_r_overflow_i ; + wire rach_s_axi_arready ; + wire rach_m_axi_arvalid ; + wire rach_rd_en ; + wire rdch_m_axi_rready ; + wire rdch_s_axi_rvalid ; + wire rdch_wr_en ; + wire rdch_rd_en ; + wire arvalid_pkt ; + wire arready_pkt ; + wire arvalid_en ; + wire rdch_rd_ok ; + wire accept_next_pkt ; + integer rdch_free_space ; + integer rdch_commited_space ; + wire rach_re ; + wire rdch_we ; + wire rdch_re ; + + localparam ARADDR_OFFSET = C_DIN_WIDTH_RACH - AXI_ADDR_WIDTH; + localparam ARPROT_OFFSET = ARADDR_OFFSET - C_AXI_PROT_WIDTH; + + localparam RDATA_OFFSET = C_DIN_WIDTH_RDCH - AXI_DATA_WIDTH; + localparam RRESP_OFFSET = RDATA_OFFSET - C_AXI_RRESP_WIDTH; + + + generate if (IS_RD_ADDR_CH == 1) begin : axi_read_addr_channel + + // Write protection when almost full or prog_full is high + + // Read protection when almost empty or prog_empty is high + assign rach_re = m_axi_arready; + assign rach_rd_en = rach_re; + + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_RACH), + .ECC_MODE (0), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_RACH ), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_RACH), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES ("0101"), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_RACH), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_rach_dut ( + .sleep (1'b0), + .rst (rst_axil_sclk), + .wr_clk (s_aclk), + .wr_en (s_axi_arvalid), + .din (rach_din), + .full (rach_full), + .full_n (), + .prog_full (), + .wr_data_count (), + .overflow (axi_ar_overflow_i), + .wr_rst_busy (wr_rst_busy_rach), + .almost_full (), + .wr_ack (), + .rd_clk (m_aclk_int), + .rd_en (rach_rd_en), + .dout (rach_dout_pkt), + .empty (rach_empty), + .prog_empty (), + .rd_data_count (), + .underflow (axi_ar_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (1'b0), + .injectdbiterr (1'b0), + .sbiterr (), + .dbiterr () + ); + + assign rach_s_axi_arready = (FIFO_MEMORY_TYPE_RACH == "lutram") ? ~(rach_full | wr_rst_busy_rach) : ~rach_full; + assign rach_m_axi_arvalid = ~rach_empty; + assign s_axi_arready = rach_s_axi_arready; + + end endgenerate // axi_read_addr_channel + + + generate if (C_RACH_TYPE == 0) begin : grach_m_axi_arvalid + assign m_axi_arvalid = rach_m_axi_arvalid; + assign rach_dout = rach_dout_pkt; + end endgenerate // grach_m_axi_arvalid + + assign arvalid_en = 1; + + generate if (IS_RD_DATA_CH == 1) begin : axi_read_data_channel + + // Write protection when almost full or prog_full is high + assign rdch_we = rdch_m_axi_rready & m_axi_rvalid ; + + // Read protection when almost empty or prog_empty is high + assign rdch_re = rdch_s_axi_rvalid & s_axi_rready; + assign rdch_wr_en = rdch_we; + assign rdch_rd_en = rdch_re; + + +xpm_fifo_base # ( + .COMMON_CLOCK (P_COMMON_CLOCK ), + .RELATED_CLOCKS (0 ), + .FIFO_MEMORY_TYPE (P_FIFO_MEMORY_TYPE_RDCH), + .ECC_MODE (P_ECC_MODE_RDCH ), + .SIM_ASSERT_CHK (SIM_ASSERT_CHK ), + .CASCADE_HEIGHT (CASCADE_HEIGHT ), + .FIFO_WRITE_DEPTH (FIFO_DEPTH_RDCH ), + .WRITE_DATA_WIDTH (C_DIN_WIDTH_RDCH_ECC), + .WR_DATA_COUNT_WIDTH (WR_DATA_COUNT_WIDTH_RDCH), + .PROG_FULL_THRESH (PROG_FULL_THRESH_RDCH ), + .FULL_RESET_VALUE (1 ), + .USE_ADV_FEATURES (USE_ADV_FEATURES_RDCH_INT), + .READ_MODE (1 ), + .FIFO_READ_LATENCY (0 ), + .READ_DATA_WIDTH (C_DIN_WIDTH_RDCH_ECC), + .RD_DATA_COUNT_WIDTH (RD_DATA_COUNT_WIDTH_RDCH), + .PROG_EMPTY_THRESH (PROG_EMPTY_THRESH_RDCH), + .DOUT_RESET_VALUE ("" ), + .CDC_DEST_SYNC_FF (CDC_SYNC_STAGES ), + .REMOVE_WR_RD_PROT_LOGIC (0 ), + .WAKEUP_TIME (0 ), + .VERSION (0 ) + ) xpm_fifo_base_rdch_dut ( + .sleep (1'b0), + .rst (rst_axil_mclk), + .wr_clk (m_aclk_int), + .wr_en (rdch_wr_en), + .din (rdch_din), + .full (rdch_full), + .full_n (), + .prog_full (prog_full_rdch), + .wr_data_count (wr_data_count_rdch), + .overflow (axi_r_overflow_i), + .wr_rst_busy (wr_rst_busy_rdch), + .almost_full (), + .wr_ack (), + .rd_clk (s_aclk), + .rd_en (rdch_rd_en), + .dout (rdch_dout), + .empty (rdch_empty), + .prog_empty (prog_empty_rdch), + .rd_data_count (rd_data_count_rdch), + .underflow (axi_r_underflow_i), + .rd_rst_busy (), + .almost_empty (), + .data_valid (), + .injectsbiterr (injectsbiterr_rdch), + .injectdbiterr (injectdbiterr_rdch), + .sbiterr (sbiterr_rdch), + .dbiterr (dbiterr_rdch) + ); + + assign rdch_s_axi_rvalid = ~rdch_empty; + assign rdch_m_axi_rready = (FIFO_MEMORY_TYPE_RDCH == "lutram") ? ~(rdch_full | wr_rst_busy_rdch) : ~rdch_full; + assign s_axi_rvalid = rdch_s_axi_rvalid; + assign m_axi_rready = rdch_m_axi_rready; + + + end endgenerate //axi_read_data_channel + + + + + generate if (IS_AXI_LITE_RACH == 1 || (C_RACH_TYPE == 1)) begin : axi_lite_rach_output1 + assign rach_din = {s_axi_araddr, s_axi_arprot}; + assign m_axi_araddr = rach_dout[C_DIN_WIDTH_RACH-1:ARADDR_OFFSET]; + assign m_axi_arprot = rach_dout[ARADDR_OFFSET-1:ARPROT_OFFSET]; + end endgenerate // axi_lite_rach_output + + generate if (IS_AXI_LITE_RDCH == 1 || (C_RDCH_TYPE == 1)) begin : axi_lite_rdch_output1 + assign rdch_din = {m_axi_rdata, m_axi_rresp}; + assign s_axi_rdata = rdch_dout[C_DIN_WIDTH_RDCH-1:RDATA_OFFSET]; + assign s_axi_rresp = rdch_dout[RDATA_OFFSET-1:RRESP_OFFSET]; + end endgenerate // axi_lite_rdch_output + + + //end of axi_read_channel + + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + // Pass Through Logic or Wiring Logic + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // Pass Through Logic for Read Channel + //------------------------------------------------------------------------- + + // Wiring logic for Write Address Channel + generate if (C_WACH_TYPE == 2) begin : gwach_pass_through + assign m_axi_awaddr = s_axi_awaddr; + assign m_axi_awprot = s_axi_awprot; + assign s_axi_awready = m_axi_awready; + assign m_axi_awvalid = s_axi_awvalid; + end endgenerate // gwach_pass_through; + + // Wiring logic for Write Data Channel + generate if (C_WDCH_TYPE == 2) begin : gwdch_pass_through + assign m_axi_wdata = s_axi_wdata; + assign m_axi_wstrb = s_axi_wstrb; + assign s_axi_wready = m_axi_wready; + assign m_axi_wvalid = s_axi_wvalid; + end endgenerate // gwdch_pass_through; + + // Wiring logic for Write Response Channel + generate if (C_WRCH_TYPE == 2) begin : gwrch_pass_through + assign s_axi_bresp = m_axi_bresp; + assign m_axi_bready = s_axi_bready; + assign s_axi_bvalid = m_axi_bvalid; + end endgenerate // gwrch_pass_through; + + //------------------------------------------------------------------------- + // Pass Through Logic for Read Channel + //------------------------------------------------------------------------- + + // Wiring logic for Read Address Channel + generate if (C_RACH_TYPE == 2) begin : grach_pass_through + assign m_axi_araddr = s_axi_araddr; + assign m_axi_arprot = s_axi_arprot; + assign s_axi_arready = m_axi_arready; + assign m_axi_arvalid = s_axi_arvalid; + end endgenerate // grach_pass_through; + + // Wiring logic for Read Data Channel + generate if (C_RDCH_TYPE == 2) begin : grdch_pass_through + assign s_axi_rdata = m_axi_rdata; + assign s_axi_rresp = m_axi_rresp; + assign s_axi_rvalid = m_axi_rvalid; + assign m_axi_rready = s_axi_rready; + end endgenerate // grdch_pass_through; + + +endmodule //xpm_fifo_axil + +module xpm_fifo_axi_reg_slice # + ( + parameter C_DATA_WIDTH = 32, + parameter C_REG_CONFIG = 32'h00000000 + ) + ( + // System Signals + input wire ACLK, + input wire ARESET, + + // Slave side + input wire [C_DATA_WIDTH-1:0] S_PAYLOAD_DATA, + input wire S_VALID, + output wire S_READY, + + // Master side + output wire [C_DATA_WIDTH-1:0] M_PAYLOAD_DATA, + output wire M_VALID, + input wire M_READY + ); + + localparam RST_SYNC_STAGES = 5; + localparam RST_BUSY_LEN = 6; + reg [1:0] arst_sync_wr = 2'b11; + reg [RST_BUSY_LEN-1:0] sckt_wr_rst_cc = 0; + wire sync_reset; + wire extnd_reset; + + + always @(posedge ARESET or posedge ACLK) begin + if (ARESET) + arst_sync_wr <= 2'b11; + else + arst_sync_wr <= {arst_sync_wr[0], 1'b0}; + end + + always @(posedge ACLK) begin + sckt_wr_rst_cc <= {sckt_wr_rst_cc[RST_BUSY_LEN-2:0], arst_sync_wr[1]}; + end + + assign sync_reset = |sckt_wr_rst_cc[RST_BUSY_LEN-5:0] | arst_sync_wr[1]; + assign extnd_reset = |sckt_wr_rst_cc | arst_sync_wr[1]; + generate + //////////////////////////////////////////////////////////////////// + // + // Both FWD and REV mode + // + //////////////////////////////////////////////////////////////////// + if (C_REG_CONFIG == 32'h00000000) + begin + reg [1:0] state; + localparam [1:0] + ZERO = 2'b10, + ONE = 2'b11, + TWO = 2'b01; + + reg [C_DATA_WIDTH-1:0] storage_data1 = 0; + reg [C_DATA_WIDTH-1:0] storage_data2 = 0; + reg load_s1; + wire load_s2; + wire load_s1_from_s2; + reg s_ready_i; //local signal of output + wire m_valid_i; //local signal of output + + // assign local signal to its output signal + assign S_READY = s_ready_i; + assign M_VALID = m_valid_i; + + reg areset_d1; // Reset delay register + always @(posedge ACLK) begin + areset_d1 <= extnd_reset; + end + + // Load storage1 with either slave side data or from storage2 + always @(posedge ACLK) + begin + if (load_s1) + if (load_s1_from_s2) + storage_data1 <= storage_data2; + else + storage_data1 <= S_PAYLOAD_DATA; + end + + // Load storage2 with slave side data + always @(posedge ACLK) + begin + if (load_s2) + storage_data2 <= S_PAYLOAD_DATA; + end + + assign M_PAYLOAD_DATA = storage_data1; + + // Always load s2 on a valid transaction even if it's unnecessary + assign load_s2 = S_VALID & s_ready_i; + + // Loading s1 + always @ * + begin + if ( ((state == ZERO) && (S_VALID == 1)) || // Load when empty on slave transaction + // Load when ONE if we both have read and write at the same time + ((state == ONE) && (S_VALID == 1) && (M_READY == 1)) || + // Load when TWO and we have a transaction on Master side + ((state == TWO) && (M_READY == 1))) + load_s1 = 1'b1; + else + load_s1 = 1'b0; + end // always @ * + + assign load_s1_from_s2 = (state == TWO); + + // State Machine for handling output signals + always @(posedge ACLK) begin + if (sync_reset || extnd_reset) begin + s_ready_i <= 1'b0; + state <= ZERO; + end else if (areset_d1 && ~extnd_reset) begin + s_ready_i <= 1'b1; + end else begin + case (state) + // No transaction stored locally + ZERO: if (S_VALID) state <= ONE; // Got one so move to ONE + + // One transaction stored locally + ONE: begin + if (M_READY & ~S_VALID) state <= ZERO; // Read out one so move to ZERO + if (~M_READY & S_VALID) begin + state <= TWO; // Got another one so move to TWO + s_ready_i <= 1'b0; + end + end + + // TWO transaction stored locally + TWO: if (M_READY) begin + state <= ONE; // Read out one so move to ONE + s_ready_i <= 1'b1; + end + endcase // case (state) + end + end // always @ (posedge ACLK) + + assign m_valid_i = state[0]; + + end // if (C_REG_CONFIG == 1) + //////////////////////////////////////////////////////////////////// + // + // 1-stage pipeline register with bubble cycle, both FWD and REV pipelining + // Operates same as 1-deep FIFO + // + //////////////////////////////////////////////////////////////////// + else if (C_REG_CONFIG == 32'h00000001) + begin + reg [C_DATA_WIDTH-1:0] storage_data1 = 0; + reg s_ready_i; //local signal of output + reg m_valid_i; //local signal of output + + // assign local signal to its output signal + assign S_READY = s_ready_i; + assign M_VALID = m_valid_i; + + reg areset_d1; // Reset delay register + always @(posedge ACLK) begin + areset_d1 <= extnd_reset; + end + + // Load storage1 with slave side data + always @(posedge ACLK) + begin + if (sync_reset || extnd_reset) begin + s_ready_i <= 1'b0; + m_valid_i <= 1'b0; + end else if (areset_d1 && ~extnd_reset) begin + s_ready_i <= 1'b1; + end else if (m_valid_i & M_READY) begin + s_ready_i <= 1'b1; + m_valid_i <= 1'b0; + end else if (S_VALID & s_ready_i) begin + s_ready_i <= 1'b0; + m_valid_i <= 1'b1; + end + if (~m_valid_i) begin + storage_data1 <= S_PAYLOAD_DATA; + end + end + assign M_PAYLOAD_DATA = storage_data1; + end // if (C_REG_CONFIG == 7) + + else begin : default_case + // Passthrough + assign M_PAYLOAD_DATA = S_PAYLOAD_DATA; + assign M_VALID = S_VALID; + assign S_READY = M_READY; + end + + endgenerate +endmodule // reg_slice +`default_nettype wire diff --git a/xpm/xpm_memory.sv b/xpm/xpm_memory.sv new file mode 100644 index 0000000..188cceb --- /dev/null +++ b/xpm/xpm_memory.sv @@ -0,0 +1,9134 @@ +//------------------------------------------------------------------------------ +// (c) Copyright 2015 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. +//------------------------------------------------------------------------------ + +// *************************** +// * DO NOT MODIFY THIS FILE * +// *************************** + +`timescale 1ps/1ps +`default_nettype none + +(* XPM_MODULE = "TRUE", KEEP_HIERARCHY = "SOFT" *) +module xpm_memory_base # ( + + // Common module parameters + parameter integer MEMORY_TYPE = 2, + parameter integer MEMORY_SIZE = 2048, + parameter integer MEMORY_PRIMITIVE = 0, + parameter integer CLOCKING_MODE = 0, + parameter integer ECC_MODE = 0, + parameter MEMORY_INIT_FILE = "none", + parameter MEMORY_INIT_PARAM = "", + parameter integer IGNORE_INIT_SYNTH = 0, + parameter integer USE_MEM_INIT_MMI = 0, + parameter integer USE_MEM_INIT = 1, + parameter MEMORY_OPTIMIZATION = "true", + parameter integer WAKEUP_TIME = 0, + parameter integer AUTO_SLEEP_TIME = 0, + parameter integer MESSAGE_CONTROL = 0, + parameter integer VERSION = 0, + parameter integer USE_EMBEDDED_CONSTRAINT = 0, + parameter integer CASCADE_HEIGHT = 0, + parameter integer SIM_ASSERT_CHK = 0, + parameter integer WRITE_PROTECT = 1, + // Port A module parameters + parameter integer WRITE_DATA_WIDTH_A = 32, + parameter integer READ_DATA_WIDTH_A = WRITE_DATA_WIDTH_A, + parameter integer BYTE_WRITE_WIDTH_A = WRITE_DATA_WIDTH_A, + parameter integer ADDR_WIDTH_A = $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_A), + parameter READ_RESET_VALUE_A = "0", + parameter integer READ_LATENCY_A = 2, + parameter integer WRITE_MODE_A = 2, + parameter RST_MODE_A = "SYNC", + + // Port B module parameters + parameter integer WRITE_DATA_WIDTH_B = WRITE_DATA_WIDTH_A, + parameter integer READ_DATA_WIDTH_B = WRITE_DATA_WIDTH_B, + parameter integer BYTE_WRITE_WIDTH_B = WRITE_DATA_WIDTH_B, + parameter integer ADDR_WIDTH_B = $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_B), + parameter READ_RESET_VALUE_B = "0", + parameter integer READ_LATENCY_B = READ_LATENCY_A, + parameter integer WRITE_MODE_B = WRITE_MODE_A, + parameter RST_MODE_B = "SYNC" +) ( + + // Common module ports + input wire sleep, + + // Port A module ports + input wire clka, + input wire rsta, + input wire ena, + input wire regcea, + input wire [(WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A)-1:0] wea, + input wire [ADDR_WIDTH_A-1:0] addra, + input wire [WRITE_DATA_WIDTH_A-1:0] dina, + input wire injectsbiterra, + input wire injectdbiterra, + output wire [READ_DATA_WIDTH_A-1:0] douta, + output wire sbiterra, + output wire dbiterra, + + // Port B module ports + input wire clkb, + input wire rstb, + input wire enb, + input wire regceb, + input wire [(WRITE_DATA_WIDTH_B/BYTE_WRITE_WIDTH_B)-1:0] web, + input wire [ADDR_WIDTH_B-1:0] addrb, + input wire [WRITE_DATA_WIDTH_B-1:0] dinb, + input wire injectsbiterrb, + input wire injectdbiterrb, + output wire [READ_DATA_WIDTH_B-1:0] doutb, + output wire sbiterrb, + output wire dbiterrb +); + + // ------------------------------------------------------------------------------------------------------------------- + // Macro definitions + // ------------------------------------------------------------------------------------------------------------------- + + // Define macros for parameter value size comparisons + `define MAX(a,b) {(a) > (b) ? (a) : (b)} + `define MIN(a,b) {(a) < (b) ? (a) : (b)} + + // Define macros to simplify variable vector slicing + `define ONE_ROW_OF_DIN row*P_MIN_WIDTH_DATA +: P_MIN_WIDTH_DATA + `define ONE_COL_OF_DINA col*P_WIDTH_COL_WRITE_A +: P_WIDTH_COL_WRITE_A + `define ONE_COL_OF_DINB col*P_WIDTH_COL_WRITE_B +: P_WIDTH_COL_WRITE_B + `define ONE_ROW_COL_OF_DINA (row*P_MIN_WIDTH_DATA+col*P_WIDTH_COL_WRITE_A) +: P_WIDTH_COL_WRITE_A + `define ONE_ROW_COL_OF_DINB (row*P_MIN_WIDTH_DATA+col*P_WIDTH_COL_WRITE_B) +: P_WIDTH_COL_WRITE_B + + // Define macros to meaningfully designate the memory type and primitive + `define MEM_TYPE_RAM_SP (MEMORY_TYPE == 0) + `define MEM_TYPE_RAM_SDP (MEMORY_TYPE == 1) + `define MEM_TYPE_RAM_TDP (MEMORY_TYPE == 2) + `define MEM_TYPE_ROM_SP (MEMORY_TYPE == 3) + `define MEM_TYPE_ROM_DP (MEMORY_TYPE == 4) + `define MEM_TYPE_RAM (`MEM_TYPE_RAM_SP || `MEM_TYPE_RAM_SDP || `MEM_TYPE_RAM_TDP) + `define MEM_TYPE_ROM (`MEM_TYPE_ROM_SP || `MEM_TYPE_ROM_DP) + `define MEM_PRIM_AUTO (MEMORY_PRIMITIVE == 0) + `define MEM_PRIM_DISTRIBUTED (MEMORY_PRIMITIVE == 1) + `define MEM_PRIM_BLOCK (MEMORY_PRIMITIVE == 2) + `define MEM_PRIM_ULTRA (MEMORY_PRIMITIVE == 3) + `define MEM_PRIM_MIXED (MEMORY_PRIMITIVE == 4) + `define WRITE_PROT_ENABLED (WRITE_PROTECT == 1) + `define WRITE_PROT_DISABLED (WRITE_PROTECT == 0) + + // Define macros to meaningfully designate port A characteristics + `define MEM_PORTA_WRITE (`MEM_TYPE_RAM_SP || `MEM_TYPE_RAM_SDP || `MEM_TYPE_RAM_TDP) + `define MEM_PORTA_READ (`MEM_TYPE_RAM_SP || `MEM_TYPE_RAM_TDP || `MEM_TYPE_ROM) + `define MEM_PORTA_WF (WRITE_MODE_A == 0) + `define MEM_PORTA_RF (WRITE_MODE_A == 1) + `define MEM_PORTA_NC (WRITE_MODE_A == 2) + `define MEM_PORTA_WR_NARROW (P_NUM_ROWS_WRITE_A == 1) + `define MEM_PORTA_WR_WIDE (P_NUM_ROWS_WRITE_A > 1) + `define MEM_PORTA_WR_WORD (P_ENABLE_BYTE_WRITE_A == 0) + `define MEM_PORTA_WR_BYTE (P_ENABLE_BYTE_WRITE_A == 1) + `define MEM_PORTA_RD_NARROW (P_NUM_ROWS_READ_A == 1) + `define MEM_PORTA_RD_WIDE (P_NUM_ROWS_READ_A > 1) + `define MEM_PORTA_RD_COMB (READ_LATENCY_A == 0) + `define MEM_PORTA_RD_REG (READ_LATENCY_A == 1) + `define MEM_PORTA_RD_PIPE (READ_LATENCY_A > 1) + + // Define macros to meaningfully designate port B characteristics + `define MEM_PORTB_WRITE (`MEM_TYPE_RAM_TDP && !`MEM_PRIM_DISTRIBUTED) + `define MEM_PORTB_READ (`MEM_TYPE_RAM_SDP || `MEM_TYPE_RAM_TDP || `MEM_TYPE_ROM_DP) + `define MEM_PORTB_WF (WRITE_MODE_B == 0) + `define MEM_PORTB_RF (WRITE_MODE_B == 1) + `define MEM_PORTB_NC (WRITE_MODE_B == 2) + `define MEM_PORTB_WR_NARROW (P_NUM_ROWS_WRITE_B == 1) + `define MEM_PORTB_WR_WIDE (P_NUM_ROWS_WRITE_B > 1) + `define MEM_PORTB_WR_WORD (P_ENABLE_BYTE_WRITE_B == 0) + `define MEM_PORTB_WR_BYTE (P_ENABLE_BYTE_WRITE_B == 1) + `define MEM_PORTB_RD_NARROW (P_NUM_ROWS_READ_B == 1) + `define MEM_PORTB_RD_WIDE (P_NUM_ROWS_READ_B > 1) + `define MEM_PORTB_RD_COMB (READ_LATENCY_B == 0) + `define MEM_PORTB_RD_REG (READ_LATENCY_B == 1) + `define MEM_PORTB_RD_PIPE (READ_LATENCY_B > 1) + `define MEM_PORTB_URAM_LAT (READ_LATENCY_B > 2) + + // Define macros to meaningfully designate other code characteristics + `define COMMON_CLOCK (CLOCKING_MODE == 0) + `define INDEPENDENT_CLOCKS (CLOCKING_MODE == 1) + `define NO_MEMORY_INIT ((MEMORY_INIT_FILE == "none" || MEMORY_INIT_FILE == "NONE" || MEMORY_INIT_FILE == "None") && (MEMORY_INIT_PARAM == "" || MEMORY_INIT_PARAM == "0")) + `define REPORT_MESSAGES (MESSAGE_CONTROL == 1) + `define NO_MESSAGES (MESSAGE_CONTROL == 0) + `define EN_INIT_MESSAGE (USE_MEM_INIT == 1) + `define MEM_PORTA_ASYM_BWE ((WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_A) && (WRITE_DATA_WIDTH_A > BYTE_WRITE_WIDTH_A) && (`MEM_PORTA_WRITE && `MEM_PORTA_READ)) + `define MEM_PORTB_ASYM_BWE ((WRITE_DATA_WIDTH_B != READ_DATA_WIDTH_B) && (WRITE_DATA_WIDTH_B > BYTE_WRITE_WIDTH_B) && (`MEM_PORTB_WRITE && `MEM_PORTB_READ)) + `define MEM_ACRSS_PORT_ASYM_BWE ((((WRITE_DATA_WIDTH_A != WRITE_DATA_WIDTH_B) && `MEM_PORTA_WRITE && `MEM_PORTB_WRITE) || ((WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) && `MEM_PORTA_WRITE && `MEM_PORTB_READ)) && ((WRITE_DATA_WIDTH_A > BYTE_WRITE_WIDTH_A) || (WRITE_DATA_WIDTH_B > BYTE_WRITE_WIDTH_B))) + `define MEM_PORT_ASYM_BWE (`MEM_PORTA_ASYM_BWE || `MEM_PORTB_ASYM_BWE || `MEM_ACRSS_PORT_ASYM_BWE) + + `define MEM_PORTA_ASYM ((WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_A) && (`MEM_PORTA_WRITE && `MEM_PORTA_READ)) + `define MEM_PORTB_ASYM ((WRITE_DATA_WIDTH_B != READ_DATA_WIDTH_B) && (`MEM_PORTB_WRITE && `MEM_PORTB_READ)) + `define MEM_ACRSS_PORT_ASYM ((((WRITE_DATA_WIDTH_A != WRITE_DATA_WIDTH_B) && `MEM_PORTA_WRITE && `MEM_PORTB_WRITE) || ((WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) && `MEM_PORTA_WRITE && `MEM_PORTB_READ)) ) + `define MEM_PORT_ASYM (`MEM_PORTA_ASYM || `MEM_PORTB_ASYM || `MEM_ACRSS_PORT_ASYM) + + `define ROM_MEMORY_OPT (MEMORY_OPTIMIZATION == "true") + + // Define macros to meaningfully designate power saving features + `define SLEEP_MODE (WAKEUP_TIME == 2) + + // Define macros to meaningfully designate collision safety + `define IS_COLLISION_A_SAFE ((`MEM_TYPE_RAM_SDP || `MEM_TYPE_RAM_TDP) && (`MEM_PORTA_RF && `COMMON_CLOCK)) + `define IS_COLLISION_B_SAFE (`MEM_TYPE_RAM_TDP && (`MEM_PORTB_RF && `COMMON_CLOCK)) + `define IS_COLLISION_SAFE ((`MEM_TYPE_RAM_TDP && `IS_COLLISION_A_SAFE && `IS_COLLISION_B_SAFE) || (`MEM_TYPE_RAM_SDP && `IS_COLLISION_A_SAFE)) + + // Define Macros related to ECC + `define NO_ECC (ECC_MODE == 0) + `define ENC_ONLY (ECC_MODE == 1) + `define DEC_ONLY (ECC_MODE == 2) + `define BOTH_ENC_DEC (ECC_MODE == 3) + + // Macro that prevents the templates to synthesis for the configurations + // that does not have the synthesis supported coding styles e.g black box + // approach for asymmetry with byte write enable + `define DISABLE_SYNTH_TEMPL (`MEM_PORT_ASYM_BWE) + + // Auto sleep mode related parameters + `define MEM_AUTO_SLP_EN (`MEM_PRIM_ULTRA && (AUTO_SLEEP_TIME != 0)) + + //Asynchronous Reset for dout + `define ASYNC_RESET_A (RST_MODE_A == "ASYNC") + `define ASYNC_RESET_B (RST_MODE_B == "ASYNC") + + // ------------------------------------------------------------------------------------------------------------------- + // Local parameter definitions + // ------------------------------------------------------------------------------------------------------------------- + + // Define local parameters for memory declaration pragmas + localparam P_MEMORY_PRIMITIVE = `MEM_PRIM_DISTRIBUTED ? "distributed" : + (`MEM_PRIM_BLOCK ? "block" : + (`MEM_PRIM_ULTRA ? "ultra" : + (`MEM_PRIM_MIXED ? "mixed" : "auto"))); + + // Define local parameters for memory array sizing + localparam integer P_MIN_WIDTH_DATA_A = `MEM_TYPE_RAM_SDP ? WRITE_DATA_WIDTH_A : + (`MEM_TYPE_ROM ? READ_DATA_WIDTH_A : + `MIN(WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_A)); + localparam integer P_MIN_WIDTH_DATA_B = `MEM_TYPE_RAM_SDP || `MEM_TYPE_ROM_DP ? READ_DATA_WIDTH_B : + (`MEM_TYPE_RAM_SP || `MEM_TYPE_ROM_SP ? P_MIN_WIDTH_DATA_A : + `MIN(WRITE_DATA_WIDTH_B, READ_DATA_WIDTH_B)); + localparam integer P_MIN_WIDTH_DATA = `MIN(P_MIN_WIDTH_DATA_A, P_MIN_WIDTH_DATA_B); + localparam integer P_MIN_WIDTH_DATA_ECC = `NO_ECC ? P_MIN_WIDTH_DATA : `BOTH_ENC_DEC ? P_MIN_WIDTH_DATA+((WRITE_DATA_WIDTH_A/64)*8) : (`DEC_ONLY && `MEM_PORTA_WRITE) ? WRITE_DATA_WIDTH_A : (`DEC_ONLY && `MEM_PORTA_READ) ? P_MIN_WIDTH_DATA+((READ_DATA_WIDTH_A/64)*8) : (`ENC_ONLY && `MEM_PORTA_READ) ? READ_DATA_WIDTH_A : READ_DATA_WIDTH_B; + localparam integer P_MAX_DEPTH_DATA = `BOTH_ENC_DEC ? MEMORY_SIZE/P_MIN_WIDTH_DATA : MEMORY_SIZE/P_MIN_WIDTH_DATA_ECC; + localparam P_ECC_MODE = `BOTH_ENC_DEC ? "both_encode_and_decode" : `DEC_ONLY ? "decode_only" : `ENC_ONLY ? "encode_only" : "no_ecc"; + localparam P_MEMORY_OPT = (!(`ROM_MEMORY_OPT) && `MEM_TYPE_ROM) ? "no" : "yes"; + + // Define local parameters for write and read data sizing + // When ECC is enabled, Byte writes and Asymmetry are not allowed + localparam integer P_WIDTH_COL_WRITE_A = `MIN(BYTE_WRITE_WIDTH_A, P_MIN_WIDTH_DATA); + localparam integer P_WIDTH_COL_WRITE_B = `MIN(BYTE_WRITE_WIDTH_B, P_MIN_WIDTH_DATA); + localparam integer P_NUM_COLS_WRITE_A = !(`NO_ECC) ? 1 : P_MIN_WIDTH_DATA/P_WIDTH_COL_WRITE_A; + localparam integer P_NUM_COLS_WRITE_B = !(`NO_ECC) ? 1 : P_MIN_WIDTH_DATA/P_WIDTH_COL_WRITE_B; + localparam integer P_NUM_ROWS_WRITE_A = !(`NO_ECC) ? 1 : WRITE_DATA_WIDTH_A/P_MIN_WIDTH_DATA; + localparam integer P_NUM_ROWS_WRITE_B = !(`NO_ECC) ? 1 : WRITE_DATA_WIDTH_B/P_MIN_WIDTH_DATA; + localparam integer P_NUM_ROWS_READ_A = !(`NO_ECC) ? 1 : READ_DATA_WIDTH_A/P_MIN_WIDTH_DATA; + localparam integer P_NUM_ROWS_READ_B = !(`NO_ECC) ? 1 : READ_DATA_WIDTH_B/P_MIN_WIDTH_DATA; + localparam integer P_WIDTH_ADDR_WRITE_A = (`ENC_ONLY && `MEM_PORTB_READ) ? $clog2(MEMORY_SIZE/READ_DATA_WIDTH_B) : (`ENC_ONLY && `MEM_PORTA_READ) ? $clog2(MEMORY_SIZE/READ_DATA_WIDTH_A) : $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_A); + localparam integer P_WIDTH_ADDR_WRITE_B = `DEC_ONLY ? $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_A) : $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_B); + localparam integer P_WIDTH_ADDR_READ_A = (`ENC_ONLY && `MEM_PORTB_READ) ? $clog2(MEMORY_SIZE/READ_DATA_WIDTH_B) : (`ENC_ONLY && `MEM_PORTA_READ) ? $clog2(MEMORY_SIZE/READ_DATA_WIDTH_A) : $clog2(MEMORY_SIZE/READ_DATA_WIDTH_A); + localparam integer P_WIDTH_ADDR_READ_B = `DEC_ONLY ? $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_A) : $clog2(MEMORY_SIZE/READ_DATA_WIDTH_B); + localparam integer P_WIDTH_ADDR_LSB_WRITE_A = $clog2(P_NUM_ROWS_WRITE_A); + localparam integer P_WIDTH_ADDR_LSB_WRITE_B = $clog2(P_NUM_ROWS_WRITE_B); + localparam integer P_WIDTH_ADDR_LSB_READ_A = $clog2(P_NUM_ROWS_READ_A); + localparam integer P_WIDTH_ADDR_LSB_READ_B = $clog2(P_NUM_ROWS_READ_B); + + // Define local parameters for other code characteristics + localparam integer P_ENABLE_BYTE_WRITE_A = !(`NO_ECC) ? 0 : WRITE_DATA_WIDTH_A > BYTE_WRITE_WIDTH_A ? 1 : 0; + localparam integer P_ENABLE_BYTE_WRITE_B = !(`NO_ECC) ? 0 : WRITE_DATA_WIDTH_B > BYTE_WRITE_WIDTH_B ? 1 : 0; + + // Define local parameters for SDP write mode + localparam P_SDP_WRITE_MODE = (`MEM_PRIM_BLOCK && `MEM_PORTB_NC && `MEM_TYPE_RAM_SDP) ? "no" : "yes"; + + // Define local parameters for reset value conversions + localparam integer rsta_loop_iter = (READ_DATA_WIDTH_A < 4) ? 4 : (READ_DATA_WIDTH_A%4) ? (READ_DATA_WIDTH_A + (4-READ_DATA_WIDTH_A%4)) : READ_DATA_WIDTH_A; + localparam integer rstb_loop_iter = (READ_DATA_WIDTH_B < 4) ? 4 : (READ_DATA_WIDTH_B%4) ? (READ_DATA_WIDTH_B + (4-READ_DATA_WIDTH_B%4)) : READ_DATA_WIDTH_B; + // ------------------------------------------------------------------------------------------------------------------- + // Configuration DRCs + // ------------------------------------------------------------------------------------------------------------------- + + initial begin : config_drc + reg drc_err_flag; + drc_err_flag = 0; + #1; + + // notification and restrictions + if (1) + if (`MEM_PORTA_WRITE && `MEM_PORTA_READ && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_A && `NO_ECC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_A (%0d) for this configuration which uses port A write and read operations, but this release of XPM_MEMORY requires symmetric write and read data widths within each enabled port. %m", "XPM_MEMORY", 1, 2, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTB_READ && WRITE_DATA_WIDTH_B != READ_DATA_WIDTH_B && `NO_ECC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this configuration which uses port B write and read operations, but this release of XPM_MEMORY requires symmetric write and read data widths within each enabled port. %m", "XPM_MEMORY", 1, 3, WRITE_DATA_WIDTH_B, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (`MEM_TYPE_RAM_SDP && `MEM_PRIM_DISTRIBUTED && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this simple dual port RAM configuration with memory primitive set to distributed RAM, but this release of XPM_MEMORY requires symmetric write and read data widths when memory primitive set to distributed RAM. %m", "XPM_MEMORY", 1, 13, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (`MEM_TYPE_RAM_TDP && `MEM_PRIM_DISTRIBUTED && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this true dual port RAM configuration with memory primitive set to distributed RAM, but this release of XPM_MEMORY requires symmetric write and read data widths when memory primitive set to distributed RAM. %m", "XPM_MEMORY", 1, 14, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (`MEM_TYPE_ROM_DP && READ_DATA_WIDTH_A != READ_DATA_WIDTH_B) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this dual port ROM configuration , but this release of XPM_MEMORY requires symmetric read data widths when memory type is set to dual port ROM. %m", "XPM_MEMORY", 1, 15, READ_DATA_WIDTH_A, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (CASCADE_HEIGHT > 64 && `MEM_PRIM_ULTRA) begin + $error("[%s %0d-%0d] XPM_MEMORY does not support CASCADE_HEIGHT (%0d) greater than 64 for Ultra RAM configurations. %m", "XPM_MEMORY", 1, 16, CASCADE_HEIGHT); + drc_err_flag = 1; + end + + if (CASCADE_HEIGHT > 16 && `MEM_PRIM_BLOCK) begin + $error("[%s %0d-%0d] XPM_MEMORY does not support CASCADE_HEIGHT (%0d) greater than 16 for Block RAM configurations. %m", "XPM_MEMORY", 1, 16, CASCADE_HEIGHT); + drc_err_flag = 1; + end + + if (!`NO_ECC && !`NO_MEMORY_INIT) begin + $error("[%s %0d-%0d] Memory initialization is specified for this configuration with ECC (%0d) enabled, but this release of XPM_MEMORY does not support ECC with memory Initialization . %m", "XPM_MEMORY", 1, 18, ECC_MODE); + drc_err_flag = 1; + end + + if (!`NO_ECC && `MEM_TYPE_ROM) begin + $error("[%s %0d-%0d] Memory type is set to ROM for this configuration with ECC (%0d) enabled, but this release of XPM_MEMORY does not support ECC with memory Initialization . %m", "XPM_MEMORY", 1, 19, ECC_MODE); + drc_err_flag = 1; + end + + if (`MEM_PORT_ASYM_BWE && !`NO_MEMORY_INIT) begin + $error("[%s %0d-%0d] Asymmetry with Byte Write Enable is specified with Memory initialization, but this release of XPM_MEMORY does not support Memory initialization with Asymmetric Byte Write Enable. %m", "XPM_MEMORY", 1, 21); + drc_err_flag = 1; + end + + if (`MEM_PORT_ASYM_BWE && `MEM_PRIM_ULTRA && (`SLEEP_MODE || `MEM_AUTO_SLP_EN)) begin + $error("[%s %0d-%0d] The configuration has UltraRAM,Asymmetric ports with Byte Write Enable with Sleep Mode or Auto Sleep Mode enabled, but this release of XPM_MEMORY does not support the specified configuration. %m", "XPM_MEMORY", 1, 20); + drc_err_flag = 1; + end + + if ((`MEM_PRIM_AUTO || `MEM_PRIM_BLOCK || `MEM_PRIM_ULTRA) && USE_EMBEDDED_CONSTRAINT) begin + $error("[%s %0d-%0d] USE_EMBEDDED_CONSTRAINT is set to (%0d), but Embedded Constraint is supported only for distributed RAM with separate write and read clocks. %m", "XPM_MEMORY", 1, 22, USE_EMBEDDED_CONSTRAINT); + drc_err_flag = 1; + end + + if ((`MEM_PORT_ASYM_BWE && `MEM_TYPE_RAM_SDP && `MEM_PORTA_WR_BYTE && (WRITE_DATA_WIDTH_B%BYTE_WRITE_WIDTH_A != 0)) || (`MEM_PORT_ASYM_BWE && `MEM_TYPE_RAM_TDP && `MEM_PORTA_WR_BYTE && (BYTE_WRITE_WIDTH_B%BYTE_WRITE_WIDTH_A != 0)) || (`MEM_PORT_ASYM_BWE && `MEM_TYPE_RAM_TDP && `MEM_PORTB_WR_BYTE && (BYTE_WRITE_WIDTH_A%BYTE_WRITE_WIDTH_B != 0))) begin + $error("[%s %0d-%0d] Asymmetry with Byte Write Enable is specified, but the write data width and byte write width of port A and port B are not compatible. If byte write is enabled on port A, then data width of port B must be divisible by Port A byte write width, and vice versa. %m", "XPM_MEMORY", 1, 23); + drc_err_flag = 1; + end + + if (`MEM_AUTO_SLP_EN && `MEM_TYPE_RAM_SDP && `MEM_PORTB_WF && (READ_LATENCY_B < 4) ) begin + $error("[%s %0d-%0d] This configuration has Simple Dual Port RAM, UltraRAM, Write First Mode with Non-Zero Auto Sleep value and READ_LATENCY_B (%0d) value less than 4. But in this release of XPM_MEMORY does not support READ_LATENCY_B value less than 4 for the specified configuration. %m", "XPM_MEMORY", 1, 24, READ_LATENCY_B); + drc_err_flag = 1; + end + + if (`MEM_AUTO_SLP_EN && `MEM_TYPE_RAM_SDP && `MEM_PORTB_RF && (READ_LATENCY_B < 3)) begin + $error("[%s %0d-%0d] This configuration has Simple Dual Port RAM, UltraRAM, Read First Mode with Non-Zero Auto Sleep value and READ_LATENCY_B (%0d) value less than 3. But in this release of XPM_MEMORY does not support READ_LATENCY_B value less than 3 for the specified configuration. %m", "XPM_MEMORY", 1, 25, READ_LATENCY_B); + drc_err_flag = 1; + end + + if (`MEM_AUTO_SLP_EN && `MEM_TYPE_RAM_SP && (READ_LATENCY_A < 3)) begin + $error("[%s %0d-%0d] This configuration has Single Port RAM, UltraRAM with Non-Zero Auto Sleep value and READ_LATENCY_A (%0d) value less than 3. But in this release of XPM_MEMORY does not support READ_LATENCY_A value less than 3 for the specified configuration. %m", "XPM_MEMORY", 1, 26, READ_LATENCY_A); + drc_err_flag = 1; + end + + if (`MEM_AUTO_SLP_EN && `MEM_TYPE_RAM_TDP && (READ_LATENCY_A < 3)) begin + $error("[%s %0d-%0d] This configuration has True Dual Port RAM, UltraRAM with Non-Zero Auto Sleep value and READ_LATENCY_A (%0d) value less than 3. But in this release of XPM_MEMORY does not support READ_LATENCY_A value less than 3 for the specified configuration. %m", "XPM_MEMORY", 1, 27, READ_LATENCY_A); + drc_err_flag = 1; + end + + if (`MEM_AUTO_SLP_EN && `MEM_TYPE_RAM_TDP && (READ_LATENCY_B < 3)) begin + $error("[%s %0d-%0d] This configuration has True Dual Port RAM, UltraRAM with Non-Zero Auto Sleep value and READ_LATENCY_B (%0d) value less than 3. But in this release of XPM_MEMORY does not support READ_LATENCY_B value less than 3 for the specified configuration. %m", "XPM_MEMORY", 1, 28, READ_LATENCY_B); + drc_err_flag = 1; + end + + if ((WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) && `MEM_TYPE_RAM_SDP && `MEM_PORTB_WF) begin + $error("[%s %0d-%0d] This configuration has Simple Dual Port RAM, Port-B Write First Mode with WRITE_DATA_WIDTH_A (%0d) not equal to READ_DATA_WIDTH_B (%0d). But in this release of XPM_MEMORY does not support the specified configuration. %m", "XPM_MEMORY", 1, 29, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + + // Range checks + if (!(MEMORY_TYPE == 0 || MEMORY_TYPE == 1 || MEMORY_TYPE == 2 || MEMORY_TYPE == 3 || MEMORY_TYPE == 4)) begin + $error("[%s %0d-%0d] MEMORY_TYPE (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 1, MEMORY_TYPE); + drc_err_flag = 1; + end + if (!(MEMORY_SIZE > 0)) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 2, MEMORY_SIZE); + drc_err_flag = 1; + end + //if ((MEMORY_SIZE > 150994944 )) begin + // $error("[%s %0d-%0d] MEMORY_SIZE (%0d) value exceeds the maximum supported size. %m", "XPM_MEMORY", 10, 11, MEMORY_SIZE); + // drc_err_flag = 1; + //end + if (!(MEMORY_PRIMITIVE == 0 || MEMORY_PRIMITIVE == 1 || MEMORY_PRIMITIVE == 2 || MEMORY_PRIMITIVE == 3 || MEMORY_PRIMITIVE == 4)) begin + $error("[%s %0d-%0d] MEMORY_PRIMITIVE (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 3, MEMORY_PRIMITIVE); + drc_err_flag = 1; + end + if (!(CLOCKING_MODE == 0 || CLOCKING_MODE == 1)) begin + $error("[%s %0d-%0d] CLOCKING_MODE (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 4, CLOCKING_MODE); + drc_err_flag = 1; + end + if (!(ECC_MODE == 0 || ECC_MODE == 1 || ECC_MODE == 2 || ECC_MODE == 3)) begin + $error("[%s %0d-%0d] ECC_MODE (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 5, ECC_MODE); + drc_err_flag = 1; + end + if (!(WAKEUP_TIME == 0 || WAKEUP_TIME == 2)) begin + $error("[%s %0d-%0d] WAKEUP_TIME (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 7, WAKEUP_TIME); + drc_err_flag = 1; + end + if (!(MESSAGE_CONTROL == 0 || MESSAGE_CONTROL == 1)) begin + $error("[%s %0d-%0d] MESSAGE_CONTROL (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 8, MESSAGE_CONTROL); + drc_err_flag = 1; + end + if (!(VERSION == 0)) begin + $error("[%s %0d-%0d] VERSION (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 9, VERSION); + drc_err_flag = 1; + end + if (!(AUTO_SLEEP_TIME == 0 || (AUTO_SLEEP_TIME >=3 && AUTO_SLEEP_TIME < 16))) begin + $error("[%s %0d-%0d] AUTO_SLEEP_TIME (%0d) value is outside of legal range. %m", "XPM_MEMORY", 10, 10, AUTO_SLEEP_TIME); + drc_err_flag = 1; + end + if (!(WRITE_DATA_WIDTH_A > 0)) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) value is outside of legal range. %m", "XPM_MEMORY", 15, 1, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (!(READ_DATA_WIDTH_A > 0)) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_A (%0d) value is outside of legal range. %m", "XPM_MEMORY", 15, 2, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (!(BYTE_WRITE_WIDTH_A == 8 || BYTE_WRITE_WIDTH_A == 9 || BYTE_WRITE_WIDTH_A == WRITE_DATA_WIDTH_A)) begin + $error("[%s %0d-%0d] BYTE_WRITE_WIDTH_A (%0d) value is outside of legal range. %m", "XPM_MEMORY", 15, 3, BYTE_WRITE_WIDTH_A); + drc_err_flag = 1; + end + if (!(ADDR_WIDTH_A > 0)) begin + $error("[%s %0d-%0d] ADDR_WIDTH_A (%0d) value is outside of legal range. %m", "XPM_MEMORY", 15, 4, ADDR_WIDTH_A); + drc_err_flag = 1; + end + if (!(READ_LATENCY_A >= 0)) begin + $error("[%s %0d-%0d] READ_LATENCY_A (%0d) value is outside of legal range. %m", "XPM_MEMORY", 15, 6, READ_LATENCY_A); + drc_err_flag = 1; + end + if (!(WRITE_MODE_A == 0 || WRITE_MODE_A == 1 || WRITE_MODE_A == 2)) begin + $error("[%s %0d-%0d] WRITE_MODE_A (%0d) value is outside of legal range. %m", "XPM_MEMORY", 15, 7, WRITE_MODE_A); + drc_err_flag = 1; + end + if (!(WRITE_DATA_WIDTH_B > 0)) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) value is outside of legal range. %m", "XPM_MEMORY", 16, 1, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (!(READ_DATA_WIDTH_B > 0)) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_B (%0d) value is outside of legal range. %m", "XPM_MEMORY", 16, 2, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (!(BYTE_WRITE_WIDTH_B == 8 || BYTE_WRITE_WIDTH_B == 9 || BYTE_WRITE_WIDTH_B == WRITE_DATA_WIDTH_B)) begin + $error("[%s %0d-%0d] BYTE_WRITE_WIDTH_B (%0d) value is outside of legal range. %m", "XPM_MEMORY", 16, 3, BYTE_WRITE_WIDTH_B); + drc_err_flag = 1; + end + if (!(ADDR_WIDTH_B > 0)) begin + $error("[%s %0d-%0d] ADDR_WIDTH_B (%0d) value is outside of legal range. %m", "XPM_MEMORY", 16, 4, ADDR_WIDTH_B); + drc_err_flag = 1; + end + if (!(READ_LATENCY_B >= 0)) begin + $error("[%s %0d-%0d] READ_LATENCY_B (%0d) value is outside of legal range. %m", "XPM_MEMORY", 16, 6, READ_LATENCY_B); + drc_err_flag = 1; + end + if (!(WRITE_MODE_B == 0 || WRITE_MODE_B == 1 || WRITE_MODE_B == 2)) begin + $error("[%s %0d-%0d] WRITE_MODE_B (%0d) value is outside of legal range. %m", "XPM_MEMORY", 16, 7, WRITE_MODE_B); + drc_err_flag = 1; + end + + // Infos + if (`MEM_PRIM_AUTO) + $info("[%s %0d-%0d] MEMORY_PRIMITIVE (%0d) instructs Vivado Synthesis to choose the memory primitive type. Depending on their values, other XPM_MEMORY parameters may preclude the choice of certain memory primitive types. Review XPM_MEMORY documentation and parameter values to understand any limitations, or set MEMORY_PRIMITIVE to a different value. %m", "XPM_MEMORY", 20, 1, MEMORY_PRIMITIVE); + if (`NO_MEMORY_INIT && !`MEM_PRIM_ULTRA && `EN_INIT_MESSAGE) + $info("[%s %0d-%0d] MEMORY_INIT_FILE (%0s), MEMORY_INIT_PARAM together specify no memory initialization. Initial memory contents will be all 0's. %m", "XPM_MEMORY", 20, 2, MEMORY_INIT_FILE,MEMORY_INIT_PARAM); + if (`COMMON_CLOCK && `MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP) + $info("[%s %0d-%0d] XPM_MEMORY behaviorally models the port operation ordering of true dual port UltraRAM configurations by slightly delaying the common clock for port B operations only. Refer to UltraRAM documentation for details. %m", "XPM_MEMORY", 20, 3); + if (AUTO_SLEEP_TIME != 0 && `MEM_PRIM_ULTRA) begin + $info("[%s %0d-%0d] Non-zero AUTO_SLEEP_TIME (%0d) is specifed for this configuration, An input pipeline having the number of register stages equal to AUTO_SLEEP_TIME will be introduced on all the input control/data signals path except for the port-enables(en[a|b]) and reset(rst[a|b]). %m", "XPM_MEMORY", 20, 4, AUTO_SLEEP_TIME); + end + + // Warnings + if (`MEM_TYPE_ROM && `NO_MEMORY_INIT) + $warning("[%s %0d-%0d] MEMORY_INIT_FILE (%0s) specifies no memory initialization file for this ROM configuration, which will result in an empty memory that may be optimized away. %m", "XPM_MEMORY", 30, 1, MEMORY_INIT_FILE); + if (`MEM_TYPE_ROM && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_A) + $warning("[%s %0d-%0d] Non-default WRITE_DATA_WIDTH_A (%0d) value ignored for ROM configurations because write operations are not used. %m", "XPM_MEMORY", 30, 2, WRITE_DATA_WIDTH_A); + if (`MEM_TYPE_RAM_SDP && READ_DATA_WIDTH_A != WRITE_DATA_WIDTH_A) + $warning("[%s %0d-%0d] Non-default READ_DATA_WIDTH_A (%0d) value ignored for simple dual port RAM configurations because port A read operations are not used. %m", "XPM_MEMORY", 30, 3, READ_DATA_WIDTH_A); + if (`MEM_TYPE_ROM && BYTE_WRITE_WIDTH_A != WRITE_DATA_WIDTH_A) + $warning("[%s %0d-%0d] Non-default BYTE_WRITE_WIDTH_A (%0d) value ignored for ROM configurations because write operations are not used. %m", "XPM_MEMORY", 30, 4, BYTE_WRITE_WIDTH_A); + if (`MEM_TYPE_RAM_SDP && READ_RESET_VALUE_A != "0") + $warning("[%s %0d-%0d] Non-default READ_RESET_VALUE_A value ignored for simple dual port RAM configurations because port A read operations are not used. %m", "XPM_MEMORY", 30, 5); + if (`MEM_TYPE_RAM_SDP && READ_LATENCY_A != 2) + $warning("[%s %0d-%0d] Non-default READ_LATENCY_A (%0d) value ignored for simple dual port RAM configurations because port A read operations are not used. %m", "XPM_MEMORY", 30, 6, READ_LATENCY_A); + if (`MEM_TYPE_RAM_SP && WRITE_DATA_WIDTH_B != WRITE_DATA_WIDTH_A) + $warning("[%s %0d-%0d] Non-default WRITE_DATA_WIDTH_B (%0d) value ignored for single port RAM configurations because port B write operations are not used. %m", "XPM_MEMORY", 30, 7, WRITE_DATA_WIDTH_B); + if ((`MEM_TYPE_RAM_SDP || (`MEM_TYPE_RAM_TDP && `MEM_PRIM_DISTRIBUTED) || `MEM_TYPE_ROM) && WRITE_DATA_WIDTH_B != READ_DATA_WIDTH_B) + $warning("[%s %0d-%0d] Non-default WRITE_DATA_WIDTH_B (%0d) value ignored for simple dual port RAM, dual port distributed RAM, or ROM configurations because port B write operations are not used. %m", "XPM_MEMORY", 30, 8, WRITE_DATA_WIDTH_B); + if ((`MEM_TYPE_RAM_SP || `MEM_TYPE_ROM_SP) && READ_DATA_WIDTH_B != READ_DATA_WIDTH_A) + $warning("[%s %0d-%0d] Non-default READ_DATA_WIDTH_B (%0d) value ignored for single port RAM or single port ROM configurations because port B is not used. %m", "XPM_MEMORY", 30, 9, READ_DATA_WIDTH_B); + if ((`MEM_TYPE_RAM_SP || `MEM_TYPE_RAM_SDP || (`MEM_TYPE_RAM_TDP && `MEM_PRIM_DISTRIBUTED) || `MEM_TYPE_ROM) && BYTE_WRITE_WIDTH_B != WRITE_DATA_WIDTH_B) + $warning("[%s %0d-%0d] Non-default BYTE_WRITE_WIDTH_B (%0d) value ignored for single port RAM, simple dual port RAM, dual port distributed RAM, or ROM configurations because port B write operations are not used. %m", "XPM_MEMORY", 30, 10, BYTE_WRITE_WIDTH_B); + if ((`MEM_TYPE_RAM_SP || `MEM_TYPE_ROM_SP) && ADDR_WIDTH_B != $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_B)) + $warning("[%s %0d-%0d] Non-default ADDR_WIDTH_B (%0d) value ignored for single port RAM or single port ROM configurations because port B is not used. %m", "XPM_MEMORY", 30, 11, ADDR_WIDTH_B); + if ((`MEM_TYPE_RAM_SP || `MEM_TYPE_ROM_SP) && READ_RESET_VALUE_B != "0") + $warning("[%s %0d-%0d] Non-default READ_RESET_VALUE_B value ignored for single port RAM or single port ROM configurations because port B is not used. %m", "XPM_MEMORY", 30, 12); + if ((`MEM_TYPE_RAM_SP || `MEM_TYPE_ROM_SP) && READ_LATENCY_B != READ_LATENCY_A) + $warning("[%s %0d-%0d] Non-default READ_LATENCY_B (%0d) value ignored for single port RAM or single port ROM configurations because port B is not used. %m", "XPM_MEMORY", 30, 13, READ_LATENCY_B); + if ((`MEM_TYPE_RAM_SP || `MEM_TYPE_ROM) && WRITE_MODE_B != WRITE_MODE_A) + $warning("[%s %0d-%0d] Non-default WRITE_MODE_B (%0d) value ignored for single port RAM or ROM configurations because port B write operations are not used. %m", "XPM_MEMORY", 30, 14, WRITE_MODE_B); + if (`MEM_TYPE_RAM_TDP && `MEM_PRIM_DISTRIBUTED) + $warning("[%s %0d-%0d] MEMORY_TYPE (%0d) and MEMORY_PRIMITIVE (%0d) together specify a true dual port distributed RAM, which will be mapped to a dual port RAM structure using port A and B read interfaces but a single port A write interface, leaving the port B write interface unused. %m", "XPM_MEMORY", 30, 15, MEMORY_TYPE, MEMORY_PRIMITIVE); + if (`MEM_PORTA_WRITE && $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_A) < ADDR_WIDTH_A) + $warning("[%s %0d-%0d] MEMORY_SIZE (%0d), WRITE_DATA_WIDTH_A (%0d), and ADDR_WIDTH_A (%0d) together imply that the addressable range exceeds the memory size for this configuration which uses port A write operations. %m", "XPM_MEMORY", 30, 16, MEMORY_SIZE, WRITE_DATA_WIDTH_A, ADDR_WIDTH_A); + if (`MEM_PORTA_READ && $clog2(MEMORY_SIZE/READ_DATA_WIDTH_A) < ADDR_WIDTH_A) + $warning("[%s %0d-%0d] MEMORY_SIZE (%0d), READ_DATA_WIDTH_A (%0d), and ADDR_WIDTH_A (%0d) together imply that the addressable range exceeds the memory size for this configuration which uses port A read operations. %m", "XPM_MEMORY", 30, 17, MEMORY_SIZE, READ_DATA_WIDTH_A, ADDR_WIDTH_A); + if (`MEM_PORTB_WRITE && $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_B) < ADDR_WIDTH_B) + $warning("[%s %0d-%0d] MEMORY_SIZE (%0d), WRITE_DATA_WIDTH_B (%0d), and ADDR_WIDTH_B (%0d) together imply that the addressable range exceeds the memory size for this configuration which uses port B write operations. %m", "XPM_MEMORY", 30, 18, MEMORY_SIZE, WRITE_DATA_WIDTH_B, ADDR_WIDTH_B); + if (`MEM_PORTB_READ && $clog2(MEMORY_SIZE/READ_DATA_WIDTH_B) < ADDR_WIDTH_B) + $warning("[%s %0d-%0d] MEMORY_SIZE (%0d), READ_DATA_WIDTH_B (%0d), and ADDR_WIDTH_B (%0d) together imply that the addressable range exceeds the memory size for this configuration which uses port B read operations. %m", "XPM_MEMORY", 30, 19, MEMORY_SIZE, READ_DATA_WIDTH_B, ADDR_WIDTH_B); + if (`MEM_PORTA_WRITE && `MEM_PORTA_READ && `MEM_PRIM_DISTRIBUTED && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_A) + $warning("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_A (%0d) for this distributed RAM configuration configuration which uses port A write and read operations, resulting in inefficient use of memory resources. %m", "XPM_MEMORY", 30, 20, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_A); + if (`MEM_PORTA_WRITE && `MEM_PORTB_READ && `MEM_PRIM_DISTRIBUTED && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) + $warning("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this distributed RAM configuration configuration which uses port A write and port B read operations, resulting in inefficient use of memory resources. %m", "XPM_MEMORY", 30, 21, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_B); + if (`MEM_PORTA_READ && `MEM_PORTB_READ && `MEM_PRIM_DISTRIBUTED && READ_DATA_WIDTH_A != READ_DATA_WIDTH_B) + $warning("[%s %0d-%0d] READ_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this distributed memory configuration which uses port A and port B read operations, resulting in inefficient use of memory resources. %m", "XPM_MEMORY", 30, 22, READ_DATA_WIDTH_A, READ_DATA_WIDTH_B); + if (`MEM_PORTA_READ && `MEM_PORTA_RD_COMB && READ_RESET_VALUE_A != "0") + $warning("[%s %0d-%0d] Non-default READ_RESET_VALUE_A value ignored for this configuration which uses port A read operations, because READ_LATENCY_A (%0d) specifies a combinatorial read output. %m", "XPM_MEMORY", 30, 23, READ_LATENCY_A); + if (`MEM_PORTB_READ && `MEM_PORTB_RD_COMB && READ_RESET_VALUE_B != "0") + $warning("[%s %0d-%0d] Non-default READ_RESET_VALUE_B value ignored for this configuration which uses port B read operations, because READ_LATENCY_B (%0d) specifies a combinatorial read output. %m", "XPM_MEMORY", 30, 24, READ_LATENCY_B); + if (`REPORT_MESSAGES && (`MEM_TYPE_RAM_SDP || `MEM_TYPE_RAM_TDP) && !(`MEM_PRIM_DISTRIBUTED || `MEM_PRIM_ULTRA)) + $warning("[%s %0d-%0d] MESSAGE_CONTROL (%0d) specifies simulation message reporting, but any potential collisions reported for this configuration should be further investigated in netlist timing simulations for improved accuracy. %m", "XPM_MEMORY", 30, 25, MESSAGE_CONTROL); + if (WRITE_DATA_WIDTH_A > 4608 || READ_DATA_WIDTH_A > 4608) + $warning("[%s %0d-%0d] This configuration has WRITE_DATA_WIDTH_A of (%0d) and READ_DATA_WIDTH_A of (%0d), but in this release of XPM_MEMORY, the configurations having write/read data widths greater than 4608 are not completely verified. %m", "XPM_MEMORY", 30, 26, WRITE_DATA_WIDTH_A,READ_DATA_WIDTH_A); + if (WRITE_DATA_WIDTH_B > 4608 || READ_DATA_WIDTH_B > 4608) + $warning("[%s %0d-%0d] This configuration has WRITE_DATA_WIDTH_B of (%0d) and READ_DATA_WIDTH_B (%0d), but in this release of XPM_MEMORY, the configurations having write/read data widths greater than 4608 are not completely verified. %m", "XPM_MEMORY", 30, 27 , WRITE_DATA_WIDTH_B,READ_DATA_WIDTH_B); + if ( `MEM_TYPE_RAM_TDP && (BYTE_WRITE_WIDTH_A == 8 || BYTE_WRITE_WIDTH_A == 9) && (READ_DATA_WIDTH_B == BYTE_WRITE_WIDTH_B && WRITE_DATA_WIDTH_B == BYTE_WRITE_WIDTH_B) && (READ_DATA_WIDTH_B % BYTE_WRITE_WIDTH_A != 0 || WRITE_DATA_WIDTH_B % BYTE_WRITE_WIDTH_A != 0)) + $warning("[%s %0d-%0d] This configuration has byte wide writes on port-A and port-B does not have byte wide writes, but in this release of XPM_MEMORY, the configurations having byte wide writes on one port and other port not having byte wide writes is not completely verified. %m", "XPM_MEMORY", 30, 28); + if ( `MEM_TYPE_RAM_TDP && (BYTE_WRITE_WIDTH_B == 8 || BYTE_WRITE_WIDTH_B == 9) && (READ_DATA_WIDTH_A == BYTE_WRITE_WIDTH_A && WRITE_DATA_WIDTH_A == BYTE_WRITE_WIDTH_A) && (READ_DATA_WIDTH_A % BYTE_WRITE_WIDTH_B != 0 || WRITE_DATA_WIDTH_A % BYTE_WRITE_WIDTH_B != 0)) + $warning("[%s %0d-%0d] This configuration has byte wide writes on port-B and port-A does not have byte wide writes, but in this release of XPM_MEMORY, the configurations having byte wide writes on one port and other port not having byte wide writes is not completely verified. %m", "XPM_MEMORY", 30, 29); + if (AUTO_SLEEP_TIME != 0 && `MEM_PORTA_READ && READ_LATENCY_A == 2) + $warning("[%s %0d-%0d] The configuration specified is having non-zero Auto Sleep latency value with READ_LATENCY_A parameter value set to 2; There could be simulation mismatches between behavioral and post-synthesis simulations, please run netlist simulations for improved accuracy. %m", "XPM_MEMORY", 30, 30); + if (AUTO_SLEEP_TIME != 0 && `MEM_PORTB_READ && READ_LATENCY_B == 2) + $warning("[%s %0d-%0d] The configuration specified is having non-zero Auto Sleep latency value with READ_LATENCY_B parameter value set to 2; There could be simulation mismatches between behavioral and post-synthesis simulations, please run netlist simulations for improved accuracy. %m", "XPM_MEMORY", 30, 31); + + // Errors + if ((`MEM_TYPE_RAM_SP || `MEM_TYPE_ROM_SP) && `INDEPENDENT_CLOCKS) begin + $error("[%s %0d-%0d] CLOCKING_MODE (%0d) specifies independent clocks, but single port RAM or single port ROM configurations require a common clock. %m", "XPM_MEMORY", 40, 2, CLOCKING_MODE); + drc_err_flag = 1; + end + if (`MEM_PRIM_ULTRA && `INDEPENDENT_CLOCKS) begin + $error("[%s %0d-%0d] CLOCKING_MODE (%0d) specifies independent clocks, but UltraRAM configurations require a common clock. %m", "XPM_MEMORY", 40, 3, CLOCKING_MODE); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && (`MEM_PRIM_BLOCK || `MEM_PRIM_ULTRA) && `MEM_PORTA_RD_COMB) begin + $error("[%s %0d-%0d] READ_LATENCY_A (%0d) specifies a combinatorial read output for this configuration which uses port A read operations, but at least one register stage is required for block memory or UltraRAM configurations. %m", "XPM_MEMORY", 40, 5, READ_LATENCY_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && (`MEM_PRIM_BLOCK || `MEM_PRIM_ULTRA) && `MEM_PORTB_RD_COMB) begin + $error("[%s %0d-%0d] READ_LATENCY_B (%0d) specifies a combinatorial read output for this configuration which uses port B read operations, but at least one register stage is required for block memory or UltraRAM configurations. %m", "XPM_MEMORY", 40, 6, READ_LATENCY_B); + drc_err_flag = 1; + end + if (`MEM_TYPE_RAM_SDP && `MEM_PRIM_ULTRA && !`MEM_PORTB_RF && !`MEM_PORTB_WF) begin + $error("[%s %0d-%0d] WRITE_MODE_B (%0d) specifies no-change mode, but simple dual port RAM configurations targeting UltraRAM can only mimic read-first mode or write-first mode behaviour for port B. Please change WRITE_MODE_B to either read-first mode or write-first mode. %m", "XPM_MEMORY", 40, 8, WRITE_MODE_B); + drc_err_flag = 1; + end + if (`MEM_TYPE_RAM_SDP && `MEM_PRIM_ULTRA && `MEM_PORTB_WF && !`MEM_PORTB_URAM_LAT) begin + $error("[%s %0d-%0d] READ_LATENCY_B (%0d) specifies fewer than 3 stages, but simple dual port RAM configurations targeting UltraRAM and using write-first mode for port B must use a read latency of at least 3 for port B. %m", "XPM_MEMORY", 40, 9, READ_LATENCY_B); + drc_err_flag = 1; + end + if (`MEM_TYPE_ROM && !`MEM_PORTA_RF) begin + $error("[%s %0d-%0d] WRITE_MODE_A (%0d) specifies write-first mode or no-change mode, but ROM configurations must use read-first mode for port A. %m", "XPM_MEMORY", 40, 10, WRITE_MODE_A); + drc_err_flag = 1; + end + if (`MEM_TYPE_ROM_DP && !`MEM_PORTB_RF) begin + $error("[%s %0d-%0d] WRITE_MODE_B (%0d) specifies write-first mode or no-change mode, but dual port ROM configurations must use read-first mode for port B. %m", "XPM_MEMORY", 40, 11, WRITE_MODE_B); + drc_err_flag = 1; + end + if ((`MEM_TYPE_RAM_SP || `MEM_TYPE_RAM_TDP) && `MEM_PRIM_DISTRIBUTED && !`MEM_PORTA_RF) begin + $error("[%s %0d-%0d] WRITE_MODE_A (%0d) specifies write-first mode or no-change mode, but single port and dual port distributed RAM configurations must use read-first mode for port A. %m", "XPM_MEMORY", 40, 12, WRITE_MODE_A); + drc_err_flag = 1; + end + if (`MEM_TYPE_RAM_TDP && `MEM_PRIM_DISTRIBUTED && !`MEM_PORTB_RF) begin + $error("[%s %0d-%0d] WRITE_MODE_B (%0d) specifies write-first mode or no-change mode, but dual port distributed RAM configurations must use read-first mode for port B. %m", "XPM_MEMORY", 40, 13, WRITE_MODE_B); + drc_err_flag = 1; + end + if (`MEM_TYPE_RAM_TDP && `MEM_PRIM_ULTRA && !`MEM_PORTA_NC) begin + $error("[%s %0d-%0d] WRITE_MODE_A (%0d) specifies read-first mode or write-first mode, but true dual port UltraRAM configurations must use no-change mode for port A. %m", "XPM_MEMORY", 40, 14, WRITE_MODE_A); + drc_err_flag = 1; + end + if (`MEM_TYPE_RAM_TDP && `MEM_PRIM_ULTRA && !`MEM_PORTB_NC) begin + $error("[%s %0d-%0d] WRITE_MODE_B (%0d) specifies read-first mode or write-first mode, but true dual port UltraRAM configurations must use no-change mode for port B. %m", "XPM_MEMORY", 40, 15, WRITE_MODE_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && MEMORY_SIZE % WRITE_DATA_WIDTH_A != 0 && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of WRITE_DATA_WIDTH_A (%0d) for this configuration which uses port A write operations. %m", "XPM_MEMORY", 40, 16, MEMORY_SIZE, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && MEMORY_SIZE % READ_DATA_WIDTH_A != 0 && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of READ_DATA_WIDTH_A (%0d) for this configuration which uses port A read operations. %m", "XPM_MEMORY", 40, 17, MEMORY_SIZE, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && MEMORY_SIZE % WRITE_DATA_WIDTH_B != 0 && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of WRITE_DATA_WIDTH_B (%0d) for this configuration which uses port B write operations. %m", "XPM_MEMORY", 40, 18, MEMORY_SIZE, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && MEMORY_SIZE % READ_DATA_WIDTH_B != 0 && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of READ_DATA_WIDTH_B (%0d) for this configuration which uses port B read operations. %m", "XPM_MEMORY", 40, 19, MEMORY_SIZE, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_A) > ADDR_WIDTH_A && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), WRITE_DATA_WIDTH_A (%0d), and ADDR_WIDTH_A (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port A write operations. %m", "XPM_MEMORY", 40, 20, MEMORY_SIZE, WRITE_DATA_WIDTH_A, ADDR_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && $clog2(MEMORY_SIZE/READ_DATA_WIDTH_A) > ADDR_WIDTH_A && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), READ_DATA_WIDTH_A (%0d), and ADDR_WIDTH_A (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port A read operations. %m", "XPM_MEMORY", 40, 21, MEMORY_SIZE, READ_DATA_WIDTH_A, ADDR_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && MEMORY_SIZE/WRITE_DATA_WIDTH_A < 2 && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and WRITE_DATA_WIDTH_A (%0d) imply that the memory is not at least two words from the perspective of port A write operations. %m", "XPM_MEMORY", 40, 22, MEMORY_SIZE, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && MEMORY_SIZE/READ_DATA_WIDTH_A < 2 && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and READ_DATA_WIDTH_A (%0d) imply that the memory is not at least two words from the perspective of port A read operations. %m", "XPM_MEMORY", 40, 23, MEMORY_SIZE, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_B) > ADDR_WIDTH_B && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), WRITE_DATA_WIDTH_B (%0d), and ADDR_WIDTH_B (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port B write operations. %m", "XPM_MEMORY", 40, 24, MEMORY_SIZE, WRITE_DATA_WIDTH_B, ADDR_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && $clog2(MEMORY_SIZE/READ_DATA_WIDTH_B) > ADDR_WIDTH_B && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), READ_DATA_WIDTH_B (%0d), and ADDR_WIDTH_B (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port B read operations. %m", "XPM_MEMORY", 40, 25, MEMORY_SIZE, READ_DATA_WIDTH_B, ADDR_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && MEMORY_SIZE/WRITE_DATA_WIDTH_B < 2 && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and WRITE_DATA_WIDTH_B (%0d) imply that the memory is not at least two words from the perspective of port B write operations. %m", "XPM_MEMORY", 40, 26, MEMORY_SIZE, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && MEMORY_SIZE/READ_DATA_WIDTH_B < 2 && `NO_ECC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and READ_DATA_WIDTH_B (%0d) imply that the memory is not at least two words from the perspective of port B read operations. %m", "XPM_MEMORY", 40, 27, MEMORY_SIZE, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTA_READ && `MEM_PRIM_ULTRA && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_A && `NO_ECC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_A (%0d) for this configuration which uses port A write and read operations, but symmetric port widths are required for UltraRAM configurations. %m", "XPM_MEMORY", 40, 28, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTB_READ && `MEM_PRIM_ULTRA && WRITE_DATA_WIDTH_B != READ_DATA_WIDTH_B && `NO_ECC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this configuration which uses port B write and read operations, but symmetric port widths are required for UltraRAM configurations. %m", "XPM_MEMORY", 40, 31, WRITE_DATA_WIDTH_B, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && `MEM_PRIM_ULTRA && rst_val_conv_a(READ_RESET_VALUE_A) != 0) begin + $error("[%s %0d-%0d] READ_RESET_VALUE_A is nonzero for this configuration which uses port A read operations, but UltraRAM configurations require a zero-valued output register reset. %m", "XPM_MEMORY", 40, 33); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && `MEM_PRIM_ULTRA && rst_val_conv_b(READ_RESET_VALUE_B) != 0) begin + $error("[%s %0d-%0d] READ_RESET_VALUE_B is nonzero for this configuration which uses port B read operations, but UltraRAM configurations require a zero-valued output register reset. %m", "XPM_MEMORY", 40, 34); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTA_READ && `NO_ECC && !(WRITE_DATA_WIDTH_A == 32*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_A == 16*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_A == 8*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_A == 4*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_A == 2*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_A || 32*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_A || 16*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_A || 8*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_A || 4*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_A || 2*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_A)) begin + $error("[%s %0d-%0d] The ratio of WRITE_DATA_WIDTH_A (%0d) to READ_DATA_WIDTH_A (%0d) is not within the legal range of 32, 16, 8, 4, 2, 1, 1/2, 1/4, 1/8, 1/16, or 1/32 for this configuration which uses port A write and read operations. %m", "XPM_MEMORY", 40, 35, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTB_READ && `NO_ECC && !(WRITE_DATA_WIDTH_A == 32*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_A == 16*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_A == 8*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_A == 4*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_A == 2*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_B || 32*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_B || 16*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_B || 8*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_B || 4*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_B || 2*WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_B)) begin + $error("[%s %0d-%0d] The ratio of WRITE_DATA_WIDTH_A (%0d) to READ_DATA_WIDTH_B (%0d) is not within the legal range of 32, 16, 8, 4, 2, 1, 1/2, 1/4, 1/8, 1/16, or 1/32 for this configuration which uses port A write and port B read operations. %m", "XPM_MEMORY", 40, 36, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTA_READ && `NO_ECC && !(WRITE_DATA_WIDTH_B == 32*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_B == 16*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_B == 8*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_B == 4*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_B == 2*READ_DATA_WIDTH_A || WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_A || 32*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_A || 16*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_A || 8*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_A || 4*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_A || 2*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_A)) begin + $error("[%s %0d-%0d] The ratio of WRITE_DATA_WIDTH_B (%0d) to READ_DATA_WIDTH_A (%0d) is not within the legal range of 32, 16, 8, 4, 2, 1, 1/2, 1/4, 1/8, 1/16, or 1/32 for this configuration which uses port B write and port A read operations. %m", "XPM_MEMORY", 40, 37, WRITE_DATA_WIDTH_B, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTB_READ && `NO_ECC && !(WRITE_DATA_WIDTH_B == 32*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_B == 16*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_B == 8*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_B == 4*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_B == 2*READ_DATA_WIDTH_B || WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_B || 32*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_B || 16*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_B || 8*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_B || 4*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_B || 2*WRITE_DATA_WIDTH_B == READ_DATA_WIDTH_B)) begin + $error("[%s %0d-%0d] The ratio of WRITE_DATA_WIDTH_B (%0d) to READ_DATA_WIDTH_B (%0d) is not within the legal range of 32, 16, 8, 4, 2, 1, 1/2, 1/4, 1/8, 1/16, or 1/32 for this configuration which uses port B write and read operations. %m", "XPM_MEMORY", 40, 38, WRITE_DATA_WIDTH_B, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && `MEM_PORTB_READ && `NO_ECC && !(READ_DATA_WIDTH_A == 32*READ_DATA_WIDTH_A || READ_DATA_WIDTH_A == 16*READ_DATA_WIDTH_A || READ_DATA_WIDTH_A == 8*READ_DATA_WIDTH_A || READ_DATA_WIDTH_A == 4*READ_DATA_WIDTH_A || READ_DATA_WIDTH_A == 2*READ_DATA_WIDTH_A || READ_DATA_WIDTH_A == READ_DATA_WIDTH_A || 32*READ_DATA_WIDTH_A == READ_DATA_WIDTH_A || 16*READ_DATA_WIDTH_A == READ_DATA_WIDTH_A || 8*READ_DATA_WIDTH_A == READ_DATA_WIDTH_A || 4*READ_DATA_WIDTH_A == READ_DATA_WIDTH_A || 2*READ_DATA_WIDTH_A == READ_DATA_WIDTH_A)) begin + $error("[%s %0d-%0d] The ratio of READ_DATA_WIDTH_A (%0d) to READ_DATA_WIDTH_B (%0d) is not within the legal range of 32, 16, 8, 4, 2, 1, 1/2, 1/4, 1/8, 1/16, or 1/32 for this configuration which uses port A and port B read operations. %m", "XPM_MEMORY", 40, 39, READ_DATA_WIDTH_A, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && WRITE_DATA_WIDTH_A % BYTE_WRITE_WIDTH_A != 0) begin + $error("[%s %0d-%0d] BYTE_WRITE_WIDTH_A (%0d) does not result in an integer number of bytes within the specified WRITE_DATA_WIDTH_A (%0d) for this configuration which uses port A write operations. %m", "XPM_MEMORY", 40, 40, BYTE_WRITE_WIDTH_A, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && WRITE_DATA_WIDTH_B % BYTE_WRITE_WIDTH_B != 0) begin + $error("[%s %0d-%0d] BYTE_WRITE_WIDTH_B (%0d) does not result in an integer number of bytes within the specified WRITE_DATA_WIDTH_B (%0d) for this configuration which uses port B write operations. %m", "XPM_MEMORY", 40, 41, BYTE_WRITE_WIDTH_B, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (32'(MEMORY_INIT_FILE) == ".coe" || 32'(MEMORY_INIT_FILE) == ".COE") begin + $error("[%s %0d-%0d] MEMORY_INIT_FILE (%0s) specifies a file with a .coe extension, but XPM_MEMORY does not support the COE file format. %m", "XPM_MEMORY", 40, 43, MEMORY_INIT_FILE); + drc_err_flag = 1; + end + if ( (`MEM_PRIM_AUTO || `MEM_PRIM_DISTRIBUTED) && (WAKEUP_TIME != 0)) begin + $error("[%s %0d-%0d] Wake up time of (%0d) is not valid when the Memory Primitive is set to %d.", "XPM_MEMORY", 40, 42, WAKEUP_TIME,MEMORY_PRIMITIVE); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTA_READ && `MEM_PRIM_DISTRIBUTED && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_A) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_A (%0d) for this configuration which uses port A write and read operations, but symmetric port widths are required for Distributed RAM configurations. %m", "XPM_MEMORY", 40, 44, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTB_READ && `MEM_PRIM_DISTRIBUTED && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this configuration which uses port A write and port B read operations, but symmetric port widths are required for Distributed RAM configurations. %m", "XPM_MEMORY", 40, 45, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTA_READ && `MEM_PRIM_DISTRIBUTED && WRITE_DATA_WIDTH_B != READ_DATA_WIDTH_A) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) does not equal READ_DATA_WIDTH_A (%0d) for this configuration which uses port B write and port A read operations, but symmetric port widths are required for Distributed RAM configurations. %m", "XPM_MEMORY", 40, 46, WRITE_DATA_WIDTH_B, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTB_READ && `MEM_PRIM_DISTRIBUTED && WRITE_DATA_WIDTH_B != READ_DATA_WIDTH_B) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this configuration which uses port B write and read operations, but symmetric port widths are required for Distributed RAM configurations. %m", "XPM_MEMORY", 40, 47, WRITE_DATA_WIDTH_B, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if ((MEMORY_INIT_FILE != "none" && MEMORY_INIT_FILE != "NONE" && MEMORY_INIT_FILE != "None") && MEMORY_SIZE > 192*1024*1024) begin + $error("[%s %0d-%0d] Memory size of (%0d) is specified for this configuration with memory initialization, but XPM_MEMORY supports initialization up to 5 million bits only. %m", "XPM_MEMORY", 40, 48, MEMORY_SIZE); + drc_err_flag = 1; + end + if (`MEM_TYPE_RAM_SDP && `MEM_PRIM_DISTRIBUTED && !`MEM_PORTB_RF) begin + $error("[%s %0d-%0d] WRITE_MODE_B (%0d) specifies write-first or no-change mode , but Simple Dual port distributed RAM configurations must use read-first mode for port B. %m", "XPM_MEMORY", 40, 49, WRITE_MODE_B); + drc_err_flag = 1; + end + if (`MEM_TYPE_RAM_SDP && `MEM_PRIM_BLOCK && !(`MEM_PORTB_RF || `MEM_PORTB_NC)) begin + $error("[%s %0d-%0d] WRITE_MODE_B (%0d) specifies write-first mode , but Simple Dual port block RAM configurations must use read-first mode for port B. %m", "XPM_MEMORY", 40, 50, WRITE_MODE_B); + drc_err_flag = 1; + end + if ((MEMORY_INIT_PARAM != "" && MEMORY_INIT_PARAM != "0") && MEMORY_SIZE > 4*1024) begin + $error("[%s %0d-%0d] Memory size of (%0d) is specified for this configuration with memory initialization through parameter, but XPM_MEMORY supports initialization through parameter up to memory size of 4k bits only. %m", "XPM_MEMORY", 40, 51, MEMORY_SIZE); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTB_WRITE && `MEM_PORTA_WR_BYTE && `MEM_PORTB_WR_BYTE && (BYTE_WRITE_WIDTH_A != BYTE_WRITE_WIDTH_B)) begin + $error("[%s %0d-%0d] BYTE_WRITE_WIDTH_A (%0d) does not equal BYTE_WRITE_WIDTH_B (%0d) for this configuration which uses port A byte wide write and port B byte wide write operations, but symmetric byte write widths are required for this configuration. %m", "XPM_MEMORY", 40, 52, BYTE_WRITE_WIDTH_A, BYTE_WRITE_WIDTH_B); + drc_err_flag = 1; + end + + if (!(32'(MEMORY_INIT_FILE) == ".mem" || 32'(MEMORY_INIT_FILE) == ".MEM") && (MEMORY_INIT_FILE != "none" && MEMORY_INIT_FILE != "NONE" && MEMORY_INIT_FILE != "None") ) begin + $error("[%s %0d-%0d] MEMORY_INIT_FILE (%0s) specified a file without .mem extension, but XPM_MEMORY supports Initialization files with MEM file format only. %m", "XPM_MEMORY", 40, 53, MEMORY_INIT_FILE); + drc_err_flag = 1; + end + +// DRCs related to ECC + if (!(`NO_ECC) && !(`MEM_PRIM_BLOCK || `MEM_PRIM_ULTRA)) begin + $error("[%s %0d-%0d] The configuration specified has ECC_MODE(%0d) parameter is set to a non-zero value and the MEMORY_PRIMITIVE(%0d) specified is other than BlockRAM or UltraRAM, but ECC feature is supported only when the MEMORY_PRIMITIVE is set to either BlockRAM or UltraRAM . %m", "XPM_MEMORY", 41, 1, ECC_MODE, MEMORY_PRIMITIVE); + drc_err_flag = 1; + end + + if (!(`NO_ECC) && `MEM_PRIM_BLOCK && !`MEM_TYPE_RAM_SDP) begin + $error("[%s %0d-%0d] The configuration specified has ECC_MODE(%0d) parameter is set to a non-zero value, MEMORY_PRIMITIVE(%0d) set to BlockRAM and MEMORY_TYPE(%0d) specified is other than Simple Dual port RAM , but ECC feature is supported only when the MEMORY_TYPE is set to simple Dual port RAM . %m", "XPM_MEMORY", 41, 2, ECC_MODE, MEMORY_PRIMITIVE, MEMORY_TYPE); + drc_err_flag = 1; + end + + if (!(`NO_ECC) && `MEM_PRIM_ULTRA && !(`MEM_TYPE_RAM_SP || `MEM_TYPE_RAM_SDP || `MEM_TYPE_RAM_TDP)) begin + $error("[%s %0d-%0d] The configuration specified has ECC_MODE(%0d) parameter is set to a non-zero value, MEMORY_PRIMITIVE(%0d) set to ultraRAM and MEMORY_TYPE(%0d) specified is other than Simple Dual port RAM , but ECC feature is supported only when the MEMORY_TYPE is set to simple Dual port RAM . %m", "XPM_MEMORY", 41, 3, ECC_MODE, MEMORY_PRIMITIVE, MEMORY_TYPE); + drc_err_flag = 1; + end + +// Both_Enc_Dec + if (`MEM_PORTA_WRITE && `MEM_PORTA_READ && `MEM_PRIM_ULTRA && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_A && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_A (%0d) for this configuration which uses port A write and read operations with ECC mode(both encode and decode) enabled, but this configuration requires symmetric write and read data widths within each enabled port. %m", "XPM_MEMORY", 41, 4, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTB_READ && `MEM_PRIM_ULTRA && WRITE_DATA_WIDTH_B != READ_DATA_WIDTH_B && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this configuration which uses port B write and read operations with ECC(both encode and decode) enabled, but this configuration requires symmetric write and read data widths within each enabled port. %m", "XPM_MEMORY", 41, 5, WRITE_DATA_WIDTH_B, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTB_READ && `MEM_TYPE_RAM_SDP && WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_B (%0d) for this configuration which uses port A write and port B read operations with ECC(both encode and decode) enabled, but this configuration requires symmetric write and read data widths across each enabled port. %m", "XPM_MEMORY", 41, 6, WRITE_DATA_WIDTH_A, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (`MEM_PORTA_WRITE && WRITE_DATA_WIDTH_A%64 != 0 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) is not a multiple of 64 for this configuration which uses port A write with ECC mode(both encode and decode) enabled, but this configuration requires write ddata width to be multiple of 64. %m", "XPM_MEMORY", 41, 7, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && READ_DATA_WIDTH_A%64 != 0 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_A (%0d) is not a multiple of 64 for this configuration which uses port A write with ECC mode(both encode and decode) enabled, but this configuration requires write ddata width to be multiple of 64. %m", "XPM_MEMORY", 41, 8, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && WRITE_DATA_WIDTH_B%64 != 0 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) is not a multiple of 64 for this configuration which uses port A write with ECC mode(both encode and decode) enabled, but this configuration requires write ddata width to be multiple of 64. %m", "XPM_MEMORY", 41, 9, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && READ_DATA_WIDTH_B%64 != 0 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_B (%0d) is not a multiple of 64 for this configuration which uses port A write with ECC mode(both encode and decode) enabled, but this configuration requires write ddata width to be multiple of 64. %m", "XPM_MEMORY", 41, 10, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (`MEM_PORTA_WRITE && MEMORY_SIZE % WRITE_DATA_WIDTH_A != 0 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of WRITE_DATA_WIDTH_A (%0d) for this configuration which uses port A write operations. %m", "XPM_MEMORY", 41, 11, MEMORY_SIZE, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && MEMORY_SIZE % READ_DATA_WIDTH_A != 0 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of READ_DATA_WIDTH_A (%0d) for this configuration which uses port A read operations. %m", "XPM_MEMORY", 41, 12, MEMORY_SIZE, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && MEMORY_SIZE % WRITE_DATA_WIDTH_B != 0 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of WRITE_DATA_WIDTH_B (%0d) for this configuration which uses port B write operations. %m", "XPM_MEMORY", 41, 13, MEMORY_SIZE, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && MEMORY_SIZE % READ_DATA_WIDTH_B != 0 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of READ_DATA_WIDTH_B (%0d) for this configuration which uses port B read operations. %m", "XPM_MEMORY", 41, 14, MEMORY_SIZE, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_A) > ADDR_WIDTH_A && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), WRITE_DATA_WIDTH_A (%0d), and ADDR_WIDTH_A (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port A write operations. %m", "XPM_MEMORY", 41, 15, MEMORY_SIZE, WRITE_DATA_WIDTH_A, ADDR_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && $clog2(MEMORY_SIZE/READ_DATA_WIDTH_A) > ADDR_WIDTH_A && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), READ_DATA_WIDTH_A (%0d), and ADDR_WIDTH_A (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port A read operations. %m", "XPM_MEMORY", 41, 16, MEMORY_SIZE, READ_DATA_WIDTH_A, ADDR_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && MEMORY_SIZE/WRITE_DATA_WIDTH_A < 2 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and WRITE_DATA_WIDTH_A (%0d) imply that the memory is not at least two words from the perspective of port A write operations. %m", "XPM_MEMORY", 41, 17, MEMORY_SIZE, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && MEMORY_SIZE/READ_DATA_WIDTH_A < 2 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and READ_DATA_WIDTH_A (%0d) imply that the memory is not at least two words from the perspective of port A read operations. %m", "XPM_MEMORY", 41, 18, MEMORY_SIZE, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_B) > ADDR_WIDTH_B && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), WRITE_DATA_WIDTH_B (%0d), and ADDR_WIDTH_B (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port B write operations. %m", "XPM_MEMORY", 41, 19, MEMORY_SIZE, WRITE_DATA_WIDTH_B, ADDR_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && $clog2(MEMORY_SIZE/READ_DATA_WIDTH_B) > ADDR_WIDTH_B && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), READ_DATA_WIDTH_B (%0d), and ADDR_WIDTH_B (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port B read operations. %m", "XPM_MEMORY", 41, 20, MEMORY_SIZE, READ_DATA_WIDTH_B, ADDR_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && MEMORY_SIZE/WRITE_DATA_WIDTH_B < 2 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and WRITE_DATA_WIDTH_B (%0d) imply that the memory is not at least two words from the perspective of port B write operations. %m", "XPM_MEMORY", 41, 21, MEMORY_SIZE, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && MEMORY_SIZE/READ_DATA_WIDTH_B < 2 && `BOTH_ENC_DEC) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and READ_DATA_WIDTH_B (%0d) imply that the memory is not at least two words from the perspective of port B read operations. %m", "XPM_MEMORY", 41, 22, MEMORY_SIZE, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + +// Enc_Only + if (`MEM_PORTA_WRITE && `MEM_PORTA_READ && `MEM_PRIM_ULTRA && READ_DATA_WIDTH_A != (WRITE_DATA_WIDTH_A + (WRITE_DATA_WIDTH_A/64)*8) && `ENC_ONLY) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_A (%0d) does not equal WRITE_DATA_WIDTH_A + number of syndrome bits (%0d) for this configuration which uses port A write and read operations with ECC mode(encode only) enabled, but this configuration requires symmetric write and read data widths within each enabled port. %m", "XPM_MEMORY", 41, 50, READ_DATA_WIDTH_A, (WRITE_DATA_WIDTH_A + (WRITE_DATA_WIDTH_A/64)*8)); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTB_READ && `MEM_PRIM_ULTRA && READ_DATA_WIDTH_B != (WRITE_DATA_WIDTH_B + (WRITE_DATA_WIDTH_B/64)*8) && `ENC_ONLY) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_B (%0d) does not equal WRITE_DATA_WIDTH_B + number of syndrome bits (%0d) for this configuration which uses port B write and read operations with ECC(encode only) enabled, but this configuration requires symmetric write and read data widths within each enabled port. %m", "XPM_MEMORY", 41, 51, READ_DATA_WIDTH_B, (WRITE_DATA_WIDTH_B + (WRITE_DATA_WIDTH_B/64)*8)); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTB_READ && `MEM_TYPE_RAM_SDP && READ_DATA_WIDTH_B != (WRITE_DATA_WIDTH_A + (WRITE_DATA_WIDTH_A/64)*8) && `ENC_ONLY) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_B (%0d) does not equal WRITE_DATA_WIDTH_A + number of syndrome bits (%0d) for this configuration which uses port A write and port B read operations with ECC(encode only) enabled, but this configuration requires symmetric write and read data widths across each enabled port. %m", "XPM_MEMORY", 41, 52, READ_DATA_WIDTH_B, (WRITE_DATA_WIDTH_A + (WRITE_DATA_WIDTH_A/64)*8)); + drc_err_flag = 1; + end + + if (`MEM_PORTA_WRITE && WRITE_DATA_WIDTH_A%64 != 0 && `ENC_ONLY) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) is not a multiple of 64 for this configuration which uses port A write with ECC mode(encode only) enabled, but this configuration requires write data width to be multiple of 64. %m", "XPM_MEMORY", 41, 53, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && READ_DATA_WIDTH_A%72 != 0 && `ENC_ONLY) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_A (%0d) is not a multiple of 72 for this configuration which uses port A read with ECC mode(encode only) enabled, but this configuration requires read data width to be multiple of 72. %m", "XPM_MEMORY", 41, 54, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && WRITE_DATA_WIDTH_B%64 != 0 && `ENC_ONLY) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) is not a multiple of 64 for this configuration which uses port B write with ECC mode(encode only) enabled, but this configuration requires write data width to be multiple of 64. %m", "XPM_MEMORY", 41, 55, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && READ_DATA_WIDTH_B%72 != 0 && `ENC_ONLY) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_B (%0d) is not a multiple of 72 for this configuration which uses port B read with ECC mode(encode only) enabled, but this configuration requires write data width to be multiple of 72. %m", "XPM_MEMORY", 41, 56, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (`MEM_PORTA_READ && MEMORY_SIZE % READ_DATA_WIDTH_A != 0 && `ENC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of READ_DATA_WIDTH_A (%0d) for this configuration which uses port A read operations. %m", "XPM_MEMORY", 41, 57, MEMORY_SIZE, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && MEMORY_SIZE % READ_DATA_WIDTH_B != 0 && `ENC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of READ_DATA_WIDTH_B (%0d) for this configuration which uses port B read operations. %m", "XPM_MEMORY", 41, 58, MEMORY_SIZE, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && $clog2(MEMORY_SIZE/READ_DATA_WIDTH_A) > ADDR_WIDTH_A && `ENC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), READ_DATA_WIDTH_A (%0d), and ADDR_WIDTH_A (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port A read operations. %m", "XPM_MEMORY", 41, 59, MEMORY_SIZE, READ_DATA_WIDTH_A, ADDR_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && MEMORY_SIZE/READ_DATA_WIDTH_A < 2 && `ENC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and READ_DATA_WIDTH_A (%0d) imply that the memory is not at least two words from the perspective of port A read operations. %m", "XPM_MEMORY", 41, 60, MEMORY_SIZE, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && $clog2(MEMORY_SIZE/READ_DATA_WIDTH_B) > ADDR_WIDTH_B && `ENC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), READ_DATA_WIDTH_B (%0d), and ADDR_WIDTH_B (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port B read operations. %m", "XPM_MEMORY", 41, 62, MEMORY_SIZE, READ_DATA_WIDTH_B, ADDR_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && MEMORY_SIZE/READ_DATA_WIDTH_B < 2 && `ENC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and READ_DATA_WIDTH_B (%0d) imply that the memory is not at least two words from the perspective of port B read operations. %m", "XPM_MEMORY", 41, 63, MEMORY_SIZE, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + +// Dec_Only + if (`MEM_PORTA_WRITE && `MEM_PORTA_READ && `MEM_PRIM_ULTRA && WRITE_DATA_WIDTH_A != (READ_DATA_WIDTH_A + (READ_DATA_WIDTH_A/64)*8) && `DEC_ONLY) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_A + number of syndrome bits (%0d) for this configuration which uses port A write and read operations with ECC mode(decode only) enabled, but this configuration requires symmetric write and read data widths within each enabled port. %m", "XPM_MEMORY", 41, 100, WRITE_DATA_WIDTH_A, (READ_DATA_WIDTH_A + (READ_DATA_WIDTH_A/64)*8)); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && `MEM_PORTB_READ && `MEM_PRIM_ULTRA && WRITE_DATA_WIDTH_B != (READ_DATA_WIDTH_B + (READ_DATA_WIDTH_B/64)*8) && `DEC_ONLY) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) does not equal READ_DATA_WIDTH_B + number of syndrome bits (%0d) for this configuration which uses port B write and read operations with ECC(decode only) enabled, but this configuration requires symmetric write and read data widths within each enabled port. %m", "XPM_MEMORY", 41, 101, WRITE_DATA_WIDTH_B, (READ_DATA_WIDTH_B + (READ_DATA_WIDTH_B/64)*8)); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && `MEM_PORTB_READ && `MEM_TYPE_RAM_SDP && WRITE_DATA_WIDTH_A != (READ_DATA_WIDTH_B + (READ_DATA_WIDTH_B/64)*8) && `DEC_ONLY) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) does not equal READ_DATA_WIDTH_B + number of syndrome bits (%0d) for this configuration which uses port A write and port B read operations with ECC(decode only) enabled, but this configuration requires symmetric write and read data widths across each enabled port. %m", "XPM_MEMORY", 41, 102, WRITE_DATA_WIDTH_A, (READ_DATA_WIDTH_B + (READ_DATA_WIDTH_B/64)*8)); + drc_err_flag = 1; + end + + if (`MEM_PORTA_WRITE && WRITE_DATA_WIDTH_A%72 != 0 && `DEC_ONLY) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_A (%0d) is not a multiple of 72 for this configuration which uses port A write with ECC mode(decode only) enabled, but this configuration requires write data width to be multiple of 72. %m", "XPM_MEMORY", 41, 103, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_READ && READ_DATA_WIDTH_A%64 != 0 && `DEC_ONLY) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_A (%0d) is not a multiple of 64 for this configuration which uses port A read with ECC mode(decode only) enabled, but this configuration requires write data width to be multiple of 64. %m", "XPM_MEMORY", 41, 104, READ_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && WRITE_DATA_WIDTH_B%72 != 0 && `DEC_ONLY) begin + $error("[%s %0d-%0d] WRITE_DATA_WIDTH_B (%0d) is not a multiple of 72 for this configuration which uses port B write with ECC mode(decode only) enabled, but this configuration requires write data width to be multiple of 72. %m", "XPM_MEMORY", 41, 105, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_READ && READ_DATA_WIDTH_B%64 != 0 && `DEC_ONLY) begin + $error("[%s %0d-%0d] READ_DATA_WIDTH_B (%0d) is not a multiple of 64 for this configuration which uses port B write with ECC mode(decode only) enabled, but this configuration requires write data width to be multiple of 64. %m", "XPM_MEMORY", 41, 106, READ_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (`MEM_PORTA_WRITE && MEMORY_SIZE % WRITE_DATA_WIDTH_A != 0 && `DEC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of WRITE_DATA_WIDTH_A (%0d) for this configuration which uses port A write operations. %m", "XPM_MEMORY", 41, 107, MEMORY_SIZE, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && MEMORY_SIZE % WRITE_DATA_WIDTH_B != 0 && `DEC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) is not an integer multiple of WRITE_DATA_WIDTH_B (%0d) for this configuration which uses port B write operations. %m", "XPM_MEMORY", 41, 108, MEMORY_SIZE, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_A) > ADDR_WIDTH_A && `DEC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), WRITE_DATA_WIDTH_A (%0d), and ADDR_WIDTH_A (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port A write operations. %m", "XPM_MEMORY", 41, 109, MEMORY_SIZE, WRITE_DATA_WIDTH_A, ADDR_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTA_WRITE && MEMORY_SIZE/WRITE_DATA_WIDTH_A < 2 && `DEC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and WRITE_DATA_WIDTH_A (%0d) imply that the memory is not at least two words from the perspective of port A write operations. %m", "XPM_MEMORY", 41, 110, MEMORY_SIZE, WRITE_DATA_WIDTH_A); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && $clog2(MEMORY_SIZE/WRITE_DATA_WIDTH_B) > ADDR_WIDTH_B && `DEC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d), WRITE_DATA_WIDTH_B (%0d), and ADDR_WIDTH_B (%0d) together imply that the memory size exceeds its addressable range for this configuration which uses port B write operations. %m", "XPM_MEMORY", 41, 111, MEMORY_SIZE, WRITE_DATA_WIDTH_B, ADDR_WIDTH_B); + drc_err_flag = 1; + end + if (`MEM_PORTB_WRITE && MEMORY_SIZE/WRITE_DATA_WIDTH_B < 2 && `DEC_ONLY) begin + $error("[%s %0d-%0d] MEMORY_SIZE (%0d) and WRITE_DATA_WIDTH_B (%0d) imply that the memory is not at least two words from the perspective of port B write operations. %m", "XPM_MEMORY", 41, 112, MEMORY_SIZE, WRITE_DATA_WIDTH_B); + drc_err_flag = 1; + end + + if (!(`NO_ECC) && `MEM_PORTA_WRITE && (WRITE_DATA_WIDTH_A != BYTE_WRITE_WIDTH_A)) begin + $error("[%s %0d-%0d] The configuration specified has ECC_MODE(%0d) parameter is set to a non-zero value, WRITE_DATA_WIDTH_A(%0d) is not equal to BYTE_WRITE_WIDTH_A(%0d) specified, but byte wide write operations are not allowed when ECC feature is enabled . %m", "XPM_MEMORY", 41, 113, ECC_MODE, WRITE_DATA_WIDTH_A, BYTE_WRITE_WIDTH_A); + drc_err_flag = 1; + end + + if (!(`NO_ECC) && `MEM_PORTB_WRITE && (WRITE_DATA_WIDTH_B != BYTE_WRITE_WIDTH_B)) begin + $error("[%s %0d-%0d] The configuration specified has ECC_MODE(%0d) parameter is set to a non-zero value, WRITE_DATA_WIDTH_B(%0d) is not equal to BYTE_WRITE_WIDTH_B(%0d) specified, but byte wide write operations are not allowed when ECC feature is enabled . %m", "XPM_MEMORY", 41, 114, ECC_MODE, WRITE_DATA_WIDTH_B, BYTE_WRITE_WIDTH_B); + drc_err_flag = 1; + end + + if (!(`NO_ECC) && `MEM_PORTA_READ && rst_val_conv_a(READ_RESET_VALUE_A) != 0) begin + $error("[%s %0d-%0d] The configuration specified has ECC_MODE(%0d) enabled and non-zero READ_RESET_VALUE_A (%0h) value is specified, but non-zero reset value is not supported when ECC_MODE is enabled. %m", "XPM_MEMORY", 41, 115, ECC_MODE, READ_RESET_VALUE_A); + drc_err_flag = 1; + end + + if (!(`NO_ECC) && `MEM_PORTB_READ && rst_val_conv_b(READ_RESET_VALUE_B) != 0) begin + $error("[%s %0d-%0d] The configuration specified has ECC_MODE(%0d) enabled and non-zero READ_RESET_VALUE_B (%0h) value is specified, but non-zero reset value is not supported when ECC_MODE is enabled. %m", "XPM_MEMORY", 41, 116, ECC_MODE, READ_RESET_VALUE_B); + drc_err_flag = 1; + end + +// DRCs related to Auto Sleep + if (AUTO_SLEEP_TIME != 0 && !`MEM_PRIM_ULTRA) begin + $error("[%s %0d-%0d] AUTO_SLEEP_TIME (%0d) value specified is non-zero for this configuration which has MEMORY_PRIMITIVE (%0d) value other than ultraRAM, but the auto sleep feature is supported only by UltraRAM primitive. %m", "XPM_MEMORY", 40, 52, AUTO_SLEEP_TIME,MEMORY_PRIMITIVE); + drc_err_flag = 1; + end + if (AUTO_SLEEP_TIME != 0 && WAKEUP_TIME != 0) begin + $error("[%s %0d-%0d] The configuration specified has non-zero AUTO_SLEEP_TIME (%0d) and WAKEUP_TIME (%0d), but both of these features cannot co-exist. %m", "XPM_MEMORY", 40, 53, AUTO_SLEEP_TIME,WAKEUP_TIME); + drc_err_flag = 1; + end + +// DRCs related to Reset Mode + if (`ASYNC_RESET_A && !(`MEM_PRIM_BLOCK || `MEM_PRIM_ULTRA)) begin + $error("[%s %0d-%0d] The configuration specified has RST_MODE_A parameter is set ASYNC and the MEMORY_PRIMITIVE(%0d) specified is other than BlockRAM or UltraRAM, but Asynchronous Reset is supported only when the MEMORY_PRIMITIVE is set to either BlockRAM or UltraRAM . %m", "XPM_MEMORY", 40, 54, MEMORY_PRIMITIVE); + drc_err_flag = 1; + end + + if (`ASYNC_RESET_B && !(`MEM_PRIM_BLOCK || `MEM_PRIM_ULTRA)) begin + $error("[%s %0d-%0d] The configuration specified has RST_MODE_B parameter is set ASYNC and the MEMORY_PRIMITIVE(%0d) specified is other than BlockRAM or UltraRAM, but Asynchronous Reset is supported only when the MEMORY_PRIMITIVE is set to either BlockRAM or UltraRAM . %m", "XPM_MEMORY", 40, 54, MEMORY_PRIMITIVE); + drc_err_flag = 1; + end + +// DRCs related to Read Reset Value + if (`ASYNC_RESET_A && (READ_RESET_VALUE_A != "0")) begin + $error("[%s %0d-%0d] The configuration specified has RST_MODE_A parameter is set ASYNC and the READ_RESET_VALUE_A specified is Non-Zero value, but Non-Zero Reset value not allowed when RST_MODE_A is Asynchronous. %m", "XPM_MEMORY", 40, 55); + drc_err_flag = 1; + end + + if (`ASYNC_RESET_B && (READ_RESET_VALUE_B != "0")) begin + $error("[%s %0d-%0d] The configuration specified has RST_MODE_B parameter is set ASYNC and the READ_RESET_VALUE_B specified is Non-Zero value, but Non-Zero Reset value not allowed when RST_MODE_B is Asynchronous. %m", "XPM_MEMORY", 40, 56); + drc_err_flag = 1; + end + +// DRCs related to Mixed Mode Primitives + if (`MEM_PRIM_MIXED && (!`NO_ECC || AUTO_SLEEP_TIME != 0)) begin + $error("[%s %0d-%0d] ECC and Auto Sleep features not supported for Mixed Mode Primitives. %m", "XPM_MEMORY", 4, 1); + drc_err_flag = 1; + end + + if (`MEM_PRIM_MIXED && (`MEM_TYPE_ROM_SP || `MEM_TYPE_ROM_DP)) begin + $error("[%s %0d-%0d] Mixed Mode Primitives does not support ROM configurations. %m", "XPM_MEMORY", 4, 2); + drc_err_flag = 1; + end + + if (`MEM_PRIM_MIXED && ((`MEM_PORTA_WRITE && `MEM_PORTA_NC) || (`MEM_PORTB_WRITE && `MEM_PORTB_NC))) begin + $error("[%s %0d-%0d] Mixed Mode Primitives does not support No_Change on Write Mode. %m", "XPM_MEMORY", 4, 3); + drc_err_flag = 1; + end + + if (`MEM_PRIM_MIXED && ((`MEM_TYPE_RAM_TDP && (WRITE_DATA_WIDTH_A != WRITE_DATA_WIDTH_B)) || (`MEM_TYPE_RAM_SDP && (WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B)))) begin + $error("[%s %0d-%0d] Mixed Mode Primitives does not support Asymmetric Data Width. %m", "XPM_MEMORY", 4, 4); + drc_err_flag = 1; + end + + if (drc_err_flag == 1) + #1 $finish; + end : config_drc + + // ------------------------------------------------------------------------------------------------------------------- + // Memory array declaration and initialization + // ------------------------------------------------------------------------------------------------------------------- + + (* ram_style = P_MEMORY_PRIMITIVE, + rom_style = P_MEMORY_PRIMITIVE, + rw_addr_collision = P_SDP_WRITE_MODE, + ram_ecc = P_ECC_MODE, + cascade_height = CASCADE_HEIGHT, + ram_optimization = P_MEMORY_OPT *) reg [P_MIN_WIDTH_DATA_ECC-1:0] mem [0:P_MAX_DEPTH_DATA-1]; + + // Initialization through parameter + // Parameter and variable declarations + localparam NUM_CHAR_LOC = (MEMORY_INIT_PARAM == "" || MEMORY_INIT_PARAM == "0") ? 0 : (P_MIN_WIDTH_DATA%4 == 0) ? (P_MIN_WIDTH_DATA/4) : ((P_MIN_WIDTH_DATA/4)+1); + localparam MAX_NUM_CHAR = (MEMORY_INIT_PARAM == "" || MEMORY_INIT_PARAM == "0") ? 0 : P_MAX_DEPTH_DATA * NUM_CHAR_LOC + P_MAX_DEPTH_DATA; + // constants declared to eliminate the eloboration warnings in modelsim, vcs and ies + localparam P_MIN_WIDTH_DATA_SHFT = (P_MIN_WIDTH_DATA <= 4) ? 5 : P_MIN_WIDTH_DATA; + localparam P_MIN_WIDTH_DATA_LDW = (P_MIN_WIDTH_DATA <= 4) ? P_MIN_WIDTH_DATA : 4; + integer num_char_in_param=0; + + // Function to calculate the number of characters in the string + function integer num_char_init; + input [(MAX_NUM_CHAR+1)*8-1:0] str_i; + num_char_init = 0; + for(integer char_cnt=0; char_cnt<=MAX_NUM_CHAR; char_cnt=char_cnt+1) + begin + if(str_i[(char_cnt*8)+7 -: 8] != "") + num_char_init = num_char_init+1; + end + endfunction + + // Function that parses the string and returns the initialized array to the memory + function [P_MAX_DEPTH_DATA-1:0] [P_MIN_WIDTH_DATA-1:0] init_param_memory; + input [(MAX_NUM_CHAR+1)*8-1:0] mem_init_param_reg; + reg [3:0] ascii_to_binary_reg; + reg [P_MIN_WIDTH_DATA-1:0] conv_bin_val; + integer mem_location; + integer num_char; + conv_bin_val = {P_MIN_WIDTH_DATA{1'b0}}; + mem_location = 0; + num_char = 0; + for (integer init_char=MAX_NUM_CHAR+1; init_char>0; init_char = init_char-1) begin : ascii_to_bin_loop + if((mem_init_param_reg[(init_char*8)-1 -: 8] == 8'h2c) || (mem_init_param_reg[(init_char*8)-1 -: 8] == 8'h3b) || + (mem_init_param_reg[(init_char*8)-1 -: 8] == 8'h00)) begin + ascii_to_binary_reg = 4'h0; + if (num_char > 0) // Check at least for one valid character before encountering the delimiter or NULL + begin + init_param_memory[mem_location] = conv_bin_val[P_MIN_WIDTH_DATA-1:0]; + mem_location = mem_location+1; + end + conv_bin_val = {P_MIN_WIDTH_DATA{1'b0}}; + num_char = 0; + end + else if(mem_init_param_reg[(init_char*8)-1 -: 8] != 8'h00) begin + ascii_to_binary_reg = str_val_binary(mem_init_param_reg[(init_char*8)-1 -: 8]); + if (P_MIN_WIDTH_DATA <= 4) + conv_bin_val = ascii_to_binary_reg[P_MIN_WIDTH_DATA_LDW-1:0]; // converted 4-bit value from ASCII + else begin + conv_bin_val = {conv_bin_val[P_MIN_WIDTH_DATA_SHFT-5:0], ascii_to_binary_reg}; // Store the converted value in shift register + //conv_bin_val = conv_bin_val<<4 | ascii_to_binary_reg; // Store the converted value in shift register + end + num_char = num_char+1; // Increment number of characters parsed + if(num_char > NUM_CHAR_LOC) + $error("Number of characters given in the Initialization string exceeded the memory width, Please enter a valid string"); + end + end : ascii_to_bin_loop + endfunction + +generate +if(IGNORE_INIT_SYNTH == 0) begin : gen_no_ignore_init_synth + // Initialize memory array to the data file content if file name is specified, or to all zeroes if it is not specified + initial begin + if (`NO_MEMORY_INIT) begin : init_zeroes + integer initword; + for (initword=0; initword= 2) begin : gen_aslp_dly_regce + reg regcea_aslp_pipe [AUTO_SLEEP_TIME-1:0]; + // Initialize the regcea pipeline + initial begin + integer aslp_initstage_a; + for (aslp_initstage_a=0; aslp_initstage_a < AUTO_SLEEP_TIME; aslp_initstage_a=aslp_initstage_a+1) begin : for_regce_pipe_init + regcea_aslp_pipe[aslp_initstage_a] = 1'b0; + end : for_regce_pipe_init + end + // Connect the user inputs to the pipeline + always @(posedge clka) begin + regcea_aslp_pipe[0] <= regcea; + end + for (genvar aslp_stage=1; aslp_stage < AUTO_SLEEP_TIME; aslp_stage = aslp_stage+1) begin : gen_aslp_inp_pipe + always @(posedge clka) begin + regcea_aslp_pipe[aslp_stage] <= regcea_aslp_pipe[aslp_stage-1]; + end + end : gen_aslp_inp_pipe + // Assign the final pipeline output to internal regce + assign regcea_i = regcea_aslp_pipe[AUTO_SLEEP_TIME-1]; + end : gen_aslp_dly_regce + else begin : gnd_regce_ctrl + // If there are no output pipe lines, then connect to zero + assign regcea_i = 1'b0; + end : gnd_regce_ctrl + if(READ_LATENCY_A > 2) begin : gen_aslp_dly_out_pipe + reg ena_aslp_pipe [AUTO_SLEEP_TIME-1:0]; + // Initialize the ena pipeline + initial begin + integer aslp_initstage_a; + for (aslp_initstage_a=0; aslp_initstage_a < AUTO_SLEEP_TIME; aslp_initstage_a=aslp_initstage_a+1) begin : for_en_pipe_init + ena_aslp_pipe[aslp_initstage_a] = 1'b0; + end : for_en_pipe_init + end + // Connect the user inputs to the pipeline + always @(posedge clka) begin + ena_aslp_pipe[0] <= ena; + end + for (genvar aslp_stage=1; aslp_stage < AUTO_SLEEP_TIME; aslp_stage = aslp_stage+1) begin : gen_aslp_inp_pipe + always @(posedge clka) begin + ena_aslp_pipe[aslp_stage] <= ena_aslp_pipe[aslp_stage-1]; + end + end : gen_aslp_inp_pipe + // Assign the final pipeline output to internal enable that controls the + // output pipeline + assign ena_o_pipe_ctrl = ena_aslp_pipe[AUTO_SLEEP_TIME-1]; + end : gen_aslp_dly_out_pipe + else begin : gnd_pipe_en_ctrl + // If there are no output pipe lines, then connect to zero + assign ena_o_pipe_ctrl = 0; + end : gnd_pipe_en_ctrl + end : gen_aslp_rd_a + end : gen_auto_slp_dly_a + else begin : gen_nauto_slp_dly_a + // connect all the internal control signals to the ports when auto sleep is + // not enabled + assign addra_i = addra; + assign wea_i = wea; + assign dina_i = dina; + assign ena_o_pipe_ctrl = ena; + assign regcea_i = regcea; + end : gen_nauto_slp_dly_a + // Enable needs to reach URAM early compared to other inputs in Auto Sleep + // Mode, so no pipe line stages on enable irrespective auto sleep mode + // enabled/disabled + assign ena_i = ena; + + // ------------------------------------------------------------------------------------------------------------------- + // Port A write + // ------------------------------------------------------------------------------------------------------------------- + + // If the memory is any type of RAM, generate a port A write process + if (`MEM_PORTA_WRITE && !`DISABLE_SYNTH_TEMPL) begin : gen_wr_a + wire [P_WIDTH_ADDR_WRITE_A-1:0] addra_int = addra_i; + + // Synchronous port A write; word-wide write; port width is the narrowest of the data ports + if (`MEM_PORTA_WR_WORD && `MEM_PORTA_WR_NARROW && `WRITE_PROT_ENABLED) begin : gen_word_narrow + always @(posedge clka) begin + if (ena_i) begin + if (wea_i) + mem[addra_int] <= dina_i; + end + end + end : gen_word_narrow + else if (`MEM_PORTA_WR_WORD && `MEM_PORTA_WR_NARROW && `WRITE_PROT_DISABLED) begin : gen_word_narrow_wp + always @(posedge clka) begin + if (wea_i) + mem[addra_int] <= dina_i; + end + end : gen_word_narrow_wp + + // Synchronous port A write; word-wide write; port width is wider than at least one other data port; + // not generated in port A write-first read with wide data width special case + else if (`MEM_PORTA_WR_WORD && `MEM_PORTA_WR_WIDE && + !((`MEM_TYPE_RAM_SP || `MEM_TYPE_RAM_TDP) && `MEM_PORTA_WF && `MEM_PORTA_RD_WIDE) && `WRITE_PROT_ENABLED) begin : gen_word_wide + always @(posedge clka) begin : wr_sync + integer row; + reg [P_WIDTH_ADDR_LSB_WRITE_A-1:0] addralsb; + for (row=0; row= 2) begin : gen_aslp_dly_regce + reg regceb_aslp_pipe [AUTO_SLEEP_TIME-1:0]; + // Initialize the regceb pipelines + initial begin + integer aslp_initstage_b; + for (aslp_initstage_b=0; aslp_initstage_b 2) begin : gen_aslp_dly_out_pipe + reg enb_aslp_pipe [AUTO_SLEEP_TIME-1:0]; + // Initialize the enb pipelines + initial begin + integer aslp_initstage_b; + for (aslp_initstage_b=0; aslp_initstage_b 2) begin : gen_stages + always @(posedge clka) begin + if (ena_pipe[0]) + douta_pipe[0] <= douta_reg; + end + + for (genvar estage=1; estage= 2) begin : ecc_status_a_pipe + reg sbiterra_pipe [READ_LATENCY_A-2:0]; + reg dbiterra_pipe [READ_LATENCY_A-2:0]; + if (READ_LATENCY_A == 2) begin : RL_2_dly_err_status + always @(posedge clka) begin + if(rsta) begin + sbiterra_i <= 1'b0; + dbiterra_i <= 1'b0; + end + else if (regcea_i) begin + sbiterra_i <= sbiterra_in_pipe; + dbiterra_i <= dbiterra_in_pipe; + end + end + end : RL_2_dly_err_status + + if (READ_LATENCY_A > 2) begin : RL_gr_2_dly_err_status + reg ena_ecc_pipe [READ_LATENCY_A-2:0]; + always @(posedge clka) begin + ena_ecc_pipe[0] <= ena_o_pipe_ctrl; + end + + for (genvar ecc_estage_a=1; ecc_estage_a 2) begin : gen_stages + always @(posedge clkb_int) begin + if (enb_pipe[0]) + doutb_pipe[0] <= doutb_reg; + end + + for (genvar estage=1; estage 3 + if (`MEM_PORTB_WF) begin : ecc_status_wf_reg + always @(*) begin + sbiterrb_in_pipe <= sbiterrb_ram; + dbiterrb_in_pipe <= dbiterrb_ram; + end + end : ecc_status_wf_reg + + // READ_FIRST Mode + if (`MEM_PORTB_RF && `MEM_PORTB_RD_REG) begin : ecc_status_rf_reg + always @(posedge clkb_int) begin + if(rstb) begin + sbiterrb_in_pipe <= 1'b0; + dbiterrb_in_pipe <= 1'b0; + end + else if (enb_i) begin + sbiterrb_in_pipe <= sbiterrb_ram; + dbiterrb_in_pipe <= dbiterrb_ram; + end + end + end : ecc_status_rf_reg + + if (`MEM_PORTB_RF && `MEM_PORTB_RD_PIPE) begin : ecc_status_rf_pipe + always @(posedge clkb_int) begin + if (enb_i) begin + sbiterrb_in_pipe <= sbiterrb_ram; + dbiterrb_in_pipe <= dbiterrb_ram; + end + end + end : ecc_status_rf_pipe + + // NO_CHANGE Mode + if (`MEM_PORTB_NC && `MEM_PORTB_RD_REG) begin : ecc_status_nc_reg + always @(posedge clkb_int) begin + if(rstb) begin + sbiterrb_in_pipe <= 1'b0; + dbiterrb_in_pipe <= 1'b0; + end + else if (enb_i) begin + if(~(|web_i)) begin + sbiterrb_in_pipe <= sbiterrb_ram; + dbiterrb_in_pipe <= dbiterrb_ram; + end + end + end + end : ecc_status_nc_reg + + if (`MEM_PORTB_NC && `MEM_PORTB_RD_PIPE) begin : ecc_status_nc_pipe + always @(posedge clkb_int) begin + if (enb_i) begin + if(~(|web_i)) begin + sbiterrb_in_pipe <= sbiterrb_ram; + dbiterrb_in_pipe <= dbiterrb_ram; + end + end + end + end : ecc_status_nc_pipe + + // Error status signals (should be pipelined along with the data) + if (READ_LATENCY_B >= 2) begin : ecc_status_b_pipe + reg sbiterrb_pipe [READ_LATENCY_B-2:0]; + reg dbiterrb_pipe [READ_LATENCY_B-2:0]; + + if (READ_LATENCY_B == 2) begin : RL_2_dly_err_status + always @(posedge clkb_int) begin + if(rstb) begin + sbiterrb_i <= 1'b0; + dbiterrb_i <= 1'b0; + end + else if (regceb_i) begin + sbiterrb_i <= sbiterrb_in_pipe; + dbiterrb_i <= dbiterrb_in_pipe; + end + end + end : RL_2_dly_err_status + + if (READ_LATENCY_B > 2) begin : RL_gr_2_dly_err_status + reg enb_ecc_pipe [READ_LATENCY_B-2:0]; + always @(posedge clkb_int) begin + enb_ecc_pipe[0] <= enb_o_pipe_ctrl; + end + + for (genvar ecc_estage_b=1; ecc_estage_b gen_wr_a.addra_int) )) + else + $warning("XPM_MEMORY_OUT_OF_RANGE_WRITE_ACCESS : Write Operation on Port-A to an out-of-range address at time %0t; Actual Address --> %0h , effective address is %0h.There is a chance that data at the effective address location may get written in the synthesis netlist, and there by the simulation mismatch can occur between behavioral model and netlist simulations", $time,addra,gen_wr_a.addra_int); + end : illegal_wr_ena + + if (`REPORT_MESSAGES && `MEM_PORTB_WRITE && AUTO_SLEEP_TIME == 0 && !(`DISABLE_SYNTH_TEMPL)) begin : illegal_wr_enb + assert property (@(posedge gen_wr_b.clkb_int) + !(enb === 1 && |web && (addrb > gen_wr_b.addrb_int) )) + else + $warning("XPM_MEMORY_OUT_OF_RANGE_WRITE_ACCESS : Write Operation on Port-B to an out-of-range address at time %0t; Actual Address --> %0h , effective address is %0h.There is a chance that data at the effective address location may get written in the synthesis netlist, and there by the simulation mismatch can occur between behavioral model and netlist simulations", $time,addrb,gen_wr_b.addrb_int); + end : illegal_wr_enb + + // In ECC Reset is not supported and these messages are not guarded under + // MESSAGE_CONTROL param, as these are critical. + + if (!(`NO_ECC) && `MEM_PORTA_READ) begin : illegal_rsta_in_ecc + assert property (@(posedge clka) + !(rsta)) + else + $warning("XPM_MEMORY_ILLEGAL_RESET_IN_ECC_MODE : Attempt to reset the data output through Port-A at time %0t when ECC is enabled ; reset operation is not supported when ECC is enabled.", $time); + end : illegal_rsta_in_ecc + + if (!(`NO_ECC) && `MEM_PORTB_READ) begin : illegal_rstb_in_ecc + assert property (@(posedge gen_rd_b.clkb_int) + !(rstb)) + else + $warning("XPM_MEMORY_ILLEGAL_RESET_IN_ECC_MODE : Attempt to reset the data output through Port-B at time %0t when ECC is enabled ; reset operation is not supported when ECC is enabled.", $time); + end : illegal_rstb_in_ecc + + if (`REPORT_MESSAGES) begin : gen_assert_illegal_mem_access_w + // Assertion to catch illegal write access to the memory through port-B when + // the memory type is set to simple Dual port RAM + if (`MEM_TYPE_RAM_SDP) begin : illegal_mem_access_w_sdp + assert property (@(posedge clkb) + !(enb && |web)) + else + $warning("XPM_MEMORY_ILLEGAL_WRITE_SDP : Attempt to write to memory through Port-B at address 0x%0h at time %0t when the memory type is set to simple dual port RAM ; data outputs and memory content may be corrupted.", addrb, $time); + end : illegal_mem_access_w_sdp + // Assertion to catch illegal write access to the memory through port-A when + // the memory type is set to single port ROM/Dual Port ROM + if (`MEM_TYPE_ROM) begin : illegal_mem_access_w_rom + assert property (@(posedge clka) + !(ena && |wea)) + else + $warning("XPM_MEMORY_ILLEGAL_WRITE_ROM: Attempt to write to memory through Port-A at address 0x%0h at time %0t for ROM configuration ; data outputs and memory content may be corrupted.", addra, $time); + end : illegal_mem_access_w_rom + // Assertion to catch illegal write access to the memory through port-B when + // the memory type is set to Dual Port ROM + if (`MEM_TYPE_ROM_DP) begin : illegal_mem_access_w_dprom + assert property (@(posedge clkb) + !(enb && |web)) + else + $warning("XPM_MEMORY_ILLEGAL_WRITE_ROM: Attempt to write to memory through Port-B at address 0x%0h at time %0t for ROM configuration ; data outputs and memory content may be corrupted.", addrb, $time); + end : illegal_mem_access_w_dprom + + // Assertion to catch illegal REGCE assertion after Reset + + if(`MEM_PORTA_READ && `MEM_PORTA_RD_PIPE && `REPORT_MESSAGES) begin : illegal_regcea_after_rsta + reg flag_rst_regce_a = 1'b0; + // flag generation to capture the reset to valid enable duration + always @(posedge clka) + begin + if (rsta) + flag_rst_regce_a <= 1'b1; + else begin + if (gen_rd_a.gen_douta_pipe.ena_pipe[READ_LATENCY_A-2]) + flag_rst_regce_a <= 1'b0; + end + end + // Assertion + assert property (@(posedge clka) + !(~rsta && regcea && flag_rst_regce_a)) + else + $warning("regcea asserted at address 0x%0h at time %0t after reset without a valid read happened to the memory ; reset value on the output port maynot be preserved.", addra, $time); + end : illegal_regcea_after_rsta + + if(`MEM_PORTB_READ && `MEM_PORTB_RD_PIPE && `REPORT_MESSAGES) begin : illegal_regcea_after_rstb + reg flag_rst_regce_b = 1'b0; + // flag generation to capture the reset to valid enable duration + always @(posedge clkb) + begin + if (rstb) + flag_rst_regce_b <= 1'b1; + else begin + if (gen_rd_b.gen_doutb_pipe.enb_pipe[READ_LATENCY_B-2]) + flag_rst_regce_b <= 1'b0; + end + end + // Assertion + assert property (@(posedge clkb) + !(~rstb && regceb && flag_rst_regce_b)) + else + $warning("regceb asserted at address 0x%0h at time %0t after reset without a valid read happened to the memory ; reset value on the output port maynot be preserved.", addrb, $time); + end : illegal_regcea_after_rstb + + // Decode only mode can not have error injection + if (`DEC_ONLY) begin : illegal_injerr_dec_only + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra)) + else + $warning("XPM_MEMORY_ILLEGAL_ERR_INJ_ASSRT: Attempt to inject single bit error into the memory through Port-A at address 0x%0h at time %0t in Decode only mode configuration ; Error injection is not allowed in Decode only mode.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra)) + else + $warning("XPM_MEMORY_ILLEGAL_ERR_INJ_ASSRT: Attempt to inject double bit error into the memory through Port-A at address 0x%0h at time %0t in Decode only mode configuration ; Error injection is not allowed in Decode only mode.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb)) + else + $warning("XPM_MEMORY_ILLEGAL_ERR_INJ_ASSRT: Attempt to inject single bit error into the memory through Port-B at address 0x%0h at time %0t in Decode only mode configuration ; Error injection is not allowed in Decode only mode.", addrb, $time); + + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb)) + else + $warning("XPM_MEMORY_ILLEGAL_ERR_INJ_ASSRT: Attempt to inject double bit error into the memory through Port-B at address 0x%0h at time %0t in Decode only mode configuration ; Error injection is not allowed in Decode only mode.", addrb, $time); + + end : illegal_injerr_dec_only + + end : gen_assert_illegal_mem_access_w + + if ((`MEM_TYPE_RAM_TDP || `MEM_TYPE_RAM_SDP) && !(`MEM_PRIM_DISTRIBUTED || `MEM_PRIM_ULTRA)) begin : gen_assert_coll_ww + + // When port A and port B use independent clocks, capture write transactions to detect collisions + reg wra = 1'b0; + reg wrb = 1'b0; + reg rda_cap = 1'b0; + reg rdb_cap = 1'b0; + reg [(WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A)-1:0] wea_cap = 'b0; + reg [(WRITE_DATA_WIDTH_B/BYTE_WRITE_WIDTH_B)-1:0] web_cap = 'b0; + reg [P_WIDTH_ADDR_WRITE_A-1:0] addra_cap = 'b0; + reg [P_WIDTH_ADDR_WRITE_A-1:0] addra_rd_cap = 'b0; + reg [P_WIDTH_ADDR_WRITE_B-1:0] addrb_cap = 'b0; + reg [P_WIDTH_ADDR_WRITE_B-1:0] addrb_rd_cap = 'b0; + + /************************************************************************************************** + | Collision Minimum and Maximum window requirements | + | Minimum window requirement = 50 ps | + | Maximum window requirement --> | + | If the clock period is >= 3000 ps, then the window is 3000 ps | + | If the clock period is >50 ps < 3000 ps, then the window is "Clock period" ps | + **************************************************************************************************/ + integer t_half_period_a = 3000; + integer t_half_period_b = 3000; + reg clk_prd_det_a = 0; + reg clk_prd_det_b = 0; + // Determine the clock periods + initial begin + @(posedge clka); + t_half_period_a = $time/1.0; + @ (negedge clka) t_half_period_a = $time/1.0 - t_half_period_a; + clk_prd_det_a <= 1; + end + initial begin + @(posedge clkb); + t_half_period_b = $time/1.0; + @ (negedge clkb) t_half_period_b = $time/1.0 - t_half_period_b; + clk_prd_det_b <= 1; + end + + integer col_win_max = 0; + + always @(clka or clkb) begin + if(~(clk_prd_det_a && clk_prd_det_b)) begin + if(t_half_period_a > 1500 && t_half_period_b > 1500) + col_win_max = 3000; + else if(t_half_period_a <= 1500 && t_half_period_a <= t_half_period_b) + col_win_max = 2 * t_half_period_a; + else if(t_half_period_b <= 1500 && t_half_period_b <= t_half_period_a) + col_win_max = 2 * t_half_period_b; + else + col_win_max = 500; + end + end + + reg col_win_wr_a = 'b0; + reg col_win_rd_a = 'b0; + + always @(posedge clka) begin + if(ena) begin + if(|wea) begin + col_win_wr_a <= 1'b1; + col_win_wr_a <= #(col_win_max) 1'b0; + end + end + end + + always @(posedge clka) begin + if(ena) begin + if(~(|wea)) begin + col_win_rd_a <= 1'b1; + col_win_rd_a <= #(col_win_max) 1'b0; + end + end + end + + reg col_win_wr_b = 'b0; + reg col_win_rd_b = 'b0; + + always @(posedge clkb) begin + if(enb) begin + if(|web) begin + col_win_wr_b <= 1'b1; + col_win_wr_b <= #(col_win_max) 1'b0; + end + end + end + + always @(posedge clkb) begin + if(enb) begin + if(~(|web)) begin + col_win_rd_b <= 1'b1; + col_win_rd_b <= #(col_win_max) 1'b0; + end + end + end + + if (`INDEPENDENT_CLOCKS) begin : gen_wr_cap + + // Capture port A write transactions for one port A clock cycle, for purposes of detecting a collision at clock B + always @(posedge clka) begin + if (ena && |wea) begin + wra <= 1'b1; + wea_cap <= wea; + addra_cap <= addra_i; + end + else + wra <= 1'b0; + end + + // Capture port A read transactions for one port A clock cycle, for purposes of detecting a collision at clock B + always @(posedge clka) begin + rda_cap <= (ena && ~(|wea)); + if(ena && ~(|wea)) + addra_rd_cap <= addra_i; + end + + // Capture port B write transactions for one port B clock cycle, for purposes of detecting a collision at clock A + always @(posedge clkb) begin + if (enb && |web) begin + wrb <= 1'b1; + web_cap <= web; + addrb_cap <= addrb_i; + end + else + wrb <= 1'b0; + end + + // Capture port B read transactions for one port B clock cycle, for purposes of detecting a collision at clock A + always @(posedge clkb) begin + rdb_cap <= (enb && ~(|web)); + if(enb && ~(|web)) + addrb_rd_cap <= addrb_i; + end + + end : gen_wr_cap + + if(`REPORT_MESSAGES) begin : gen_coll_msgs + // Port A and port B write data widths are symmetric + if (WRITE_DATA_WIDTH_A == WRITE_DATA_WIDTH_B) begin : gen_wdw_sym + + // Port A and port B write enable widths are symmetric + if (BYTE_WRITE_WIDTH_A == BYTE_WRITE_WIDTH_B) begin : gen_we_sym + + // Port A and port B use a common clock + if (`COMMON_CLOCK) begin : gen_clock + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && |(wea & web))) + else + $warning("COLLISION: potential write-write collision to memory at time %0t (address location --> %0d); data outputs and memory content may be corrupted.", $time,addra); + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (|wea && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-A, Read happened through --> Port-B at address location %0d).", $time,addra); + + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (~(|wea) && |web ))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-B, Read happened through --> Port-A at address location %0d).", $time,addrb); + end : col_unsafe + + end : gen_clock + + // Port A and port B use independent clocks + else if (`INDEPENDENT_CLOCKS) begin : gen_clocks + + assert property (@(posedge clkb) + enb && |web && $rose(wra) |-> !((addrb == addra_cap) && |(web & wea_cap))) + else + $warning("COLLISION: potential write-write collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clka) + ena && |wea && $rose(wrb) |-> !((addra == addrb_cap) && |(wea & web_cap))) + else + $warning("COLLISION: potential write-write collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clkb) + enb && |web && $rose(rda_cap) |-> !((addrb == addra_rd_cap) && (~(|wea_cap) && |web))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clkb) + enb && ~(|web) && $rose(wra) |-> !((addrb == addra_cap) && (|wea_cap && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + + assert property (@(posedge clka) + ena && |wea && $rose(rdb_cap) |-> !((addra == addrb_rd_cap) && (|wea && ~(|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + assert property (@(posedge clka) + ena && ~(|wea) && $rose(wra) |-> !((addra == addrb_cap) && (~(|wea) && (|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + end : col_unsafe + + end : gen_clocks + end : gen_we_sym + + // Port A write enable is wider than port B write enable + else if (WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A > 1) begin : gen_we_wide_a + + // Port A and port B use a common clock + if (`COMMON_CLOCK) begin : gen_clock + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && |(wea & {(WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A){web}}))) + else + $warning("COLLISION: potential write-write collision to memory at time %0t (address location --> %0d); data outputs and memory content may be corrupted.", $time,addra); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (|wea && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-A, Read happened through --> Port-B at address location %0d).", $time,addra); + + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (~(|wea) && |web ))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-B, Read happened through --> Port-A at address location %0d).", $time,addrb); + end : col_unsafe + + end : gen_clock + + // Port A and port B use independent clocks + else if (`INDEPENDENT_CLOCKS) begin : gen_clocks + assert property (@(posedge clkb) + enb && web && $rose(wra) |-> !((addrb == addra_cap) && |({(WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A){web}} & wea_cap))) + else + $warning("COLLISION: potential write-write collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clka) + ena && |wea && $rose(wrb) |-> !((addra == addrb_cap) && |(wea & {(WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A){web_cap}}))) + else + $warning("COLLISION: potential write-write collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clkb) + enb && |web && $rose(rda_cap) |-> !((addrb == addra_rd_cap) && (~(|wea_cap) && |web))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clkb) + enb && ~(|web) && $rose(wra) |-> !((addrb == addra_cap) && (|wea_cap && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + + assert property (@(posedge clka) + ena && |wea && $rose(rdb_cap) |-> !((addra == addrb_rd_cap) && (|wea && ~(|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + assert property (@(posedge clka) + ena && ~(|wea) && $rose(wra) |-> !((addra == addrb_cap) && (~(|wea) && (|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + end : col_unsafe + + end : gen_clocks + end : gen_we_wide_a + + // Port B write enable is wider than port A write enable + else if (WRITE_DATA_WIDTH_B/BYTE_WRITE_WIDTH_B > 1) begin : gen_we_wide_b + + // Port A and port B use a common clock + if (`COMMON_CLOCK) begin : gen_clock + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && |({(WRITE_DATA_WIDTH_B/BYTE_WRITE_WIDTH_B){wea}} & web))) + else + $warning("COLLISION: potential write-write collision to memory at time %0t (address location --> %0d); data outputs and memory content may be corrupted.", $time,addra); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (|wea && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-A, Read happened through --> Port-B at address location %0d).", $time,addra); + + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (~(|wea) && |web ))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-B, Read happened through --> Port-A at address location %0d).", $time,addrb); + end : col_unsafe + end : gen_clock + + // Port A and port B use independent clocks + else if (`INDEPENDENT_CLOCKS) begin : gen_clocks + assert property (@(posedge clkb) + enb && |web && $rose(wra) |-> !((addrb == addra_cap) && |(web & {(WRITE_DATA_WIDTH_B/BYTE_WRITE_WIDTH_B){wea_cap}}))) + else + $warning("COLLISION: potential write-write collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clka) + ena && |wea && $rose(wrb) |-> !((addra == addrb_cap) && |({(WRITE_DATA_WIDTH_B/BYTE_WRITE_WIDTH_B){wea}} & web_cap))) + else + $warning("COLLISION: potential write-write collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clkb) + enb && |web && $rose(rda_cap) |-> !((addrb == addra_rd_cap) && (~(|wea_cap) && |web))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clkb) + enb && ~(|web) && $rose(wra) |-> !((addrb == addra_cap) && (|wea_cap && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + + assert property (@(posedge clka) + ena && |wea && $rose(rdb_cap) |-> !((addra == addrb_rd_cap) && (|wea && ~(|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + assert property (@(posedge clka) + ena && ~(|wea) && $rose(wra) |-> !((addra == addrb_cap) && (~(|wea) && (|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + end : col_unsafe + + end : gen_clocks + end : gen_we_wide_b + end : gen_wdw_sym + + // Port A write data is wider than port B write data + else if (WRITE_DATA_WIDTH_A > WRITE_DATA_WIDTH_B) begin : gen_wdw_wide_a + + // Port A and port B use a common clock + if (`COMMON_CLOCK) begin : gen_clock + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) && |(wea & web))) + else + $warning("COLLISION: potential write-write collision to memory at time %0t (address location --> %0d); data outputs and memory content may be corrupted.", $time,addra); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (|wea && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-A, Read happened through --> Port-B at address location %0d).", $time,addra); + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (~(|wea) && |web ))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-B, Read happened through --> Port-A at address location %0d).", $time,addrb); + + end : col_unsafe + end : gen_clock + + // Port A and port B use independent clocks + else if (`INDEPENDENT_CLOCKS) begin : gen_clocks + assert property (@(posedge clkb) + enb && |web && $rose(wra) |-> !((addra_cap == addrb >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) && |(web & wea_cap))) + else + $warning("COLLISION: potential write-write collision to memory at port A address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clka) + ena && |wea && $rose(wrb) |-> !((addra == addrb_cap >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) && |(wea & web_cap))) + else + $warning("COLLISION: potential write-write collision to memory at port B address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clkb) + enb && |web && $rose(rda_cap) |-> !((addra_rd_cap == addrb >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) && (~(|wea_cap) && |web))) + else + $warning("COLLISION: potential write-read collision to memory at port A address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clka) + ena && |wea && $rose(rdb_cap) |-> !((addra == addrb_rd_cap >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) && (|wea && ~(|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at port B address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + + assert property (@(posedge clkb) + enb && ~(|web) && $rose(wra) |-> !((addrb >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A == addra_cap) && (|wea_cap && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + + assert property (@(posedge clka) + ena && ~(|wea) && $rose(wra) |-> !((addra == addrb_cap >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) && (~(|wea) && (|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + end : col_unsafe + + end : gen_clocks + end : gen_wdw_wide_a + + // Port B write data is wider than port A write data + else if (WRITE_DATA_WIDTH_B > WRITE_DATA_WIDTH_A) begin : gen_wdw_wide_b + + // Port A and port B use a common clock + if (`COMMON_CLOCK) begin : gen_clock + assert property (@(posedge clka) + ena && enb |-> !((addrb == addra >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) && |(wea & web))) + else + $warning("COLLISION: potential write-write collision to memory at time %0t (address location --> %0d); data outputs and memory content may be corrupted.", $time,addra); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (|wea && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-A, Read happened through --> Port-B at address location %0d).", $time,addra); + + assert property (@(posedge clka) + ena && enb |-> !((addra == addrb) && (~(|wea) && |web ))) + else + $warning("COLLISION: potential write-read collision to memory at time %0t; data outputs and memory content may be corrupted (Write happened through --> Port-B, Read happened through --> Port-A at address location %0d).", $time,addrb); + end : col_unsafe + + end : gen_clock + + // Port A and port B use independent clocks + else if (`INDEPENDENT_CLOCKS) begin : gen_clocks + assert property (@(posedge clkb) + enb && |web && $rose(wra) |-> !((addrb == addra_cap >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) && |(web & wea_cap))) + else + $warning("COLLISION: potential write-write collision to memory at port A address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clka) + ena && |wea && $rose(wrb) |-> !((addrb_cap == addra >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) && |(wea & web_cap))) + else + $warning("COLLISION: potential write-write collision to memory at port B address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + + if (!`IS_COLLISION_SAFE) begin : col_unsafe + assert property (@(posedge clkb) + enb && |web && $rose(rda_cap) |-> !((addrb == addra_rd_cap >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) && (~(|wea_cap) && |web))) + else + $warning("COLLISION: potential write-read collision to memory at port A address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + assert property (@(posedge clka) + ena && |wea && $rose(rdb_cap) |-> !((addrb_rd_cap == addra >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) && (|wea && ~(|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at port B address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + + assert property (@(posedge clkb) + enb && ~(|web) && $rose(wra) |-> !((addrb == addra_cap >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) && (|wea_cap && ~(|web)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addra_cap, $time); + + assert property (@(posedge clka) + ena && ~(|wea) && $rose(wra) |-> !((addra >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B == addrb_cap) && (~(|wea) && (|web_cap)))) + else + $warning("COLLISION: potential write-read collision to memory at address 0x%0h at time %0t; data outputs and memory content may be corrupted.", addrb_cap, $time); + end : col_unsafe + + end : gen_clocks + end : gen_wdw_wide_b + end : gen_coll_msgs + +//////////////////////////////////////////////////////////////////////////////////////////// +// code is for Common clock and symmetric case +//////////////////////////////////////////////////////////////////////////////////////////// + if (`COMMON_CLOCK && (((WRITE_DATA_WIDTH_A == WRITE_DATA_WIDTH_B) && (WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_B) && (READ_DATA_WIDTH_A == WRITE_DATA_WIDTH_B) && `NO_ECC) || !`NO_ECC)) begin : sync_clk_sym + reg wr_wr_col = 0; + always @(ena or enb or addra_i or addrb_i or wea or web or dina_i or dinb_i) begin + if ((ena == 1'b1 && enb == 1'b1)) begin + if (addra_i == addrb_i) begin + if(|wea && |web) begin + force dina_i = {WRITE_DATA_WIDTH_A{1'bX}}; + force dinb_i = {WRITE_DATA_WIDTH_B{1'bX}}; + wr_wr_col <= 1'b1; + end + else begin + release dina_i; + release dinb_i; + wr_wr_col <= 1'b0; + end + end + else begin + release dina_i; + release dinb_i; + wr_wr_col <= 1'b0; + end + end + else begin + release dina_i; + release dinb_i; + wr_wr_col <= 1'b0; + end + end + + if (`MEM_PORTB_READ && !(`IS_COLLISION_SAFE)) begin : gen_rd_b_coll + always @(posedge clka) begin + if (enb == 1'b1) begin + if (ena == 1'b1 && (addra_i == addrb_i)) begin + if((|wea & ~(|web)) || wr_wr_col) begin + if(READ_LATENCY_B == 1) begin + force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + end + else begin + #1ps force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + end + end + else begin + release gen_rd_b.doutb_reg; + end + end + else begin + release gen_rd_b.doutb_reg; + end + end + end + end : gen_rd_b_coll + + if (`MEM_PORTA_READ && !(`IS_COLLISION_SAFE)) begin : gen_rd_a_coll + always @(posedge clka) begin + if (ena == 1'b1) begin + if (enb == 1'b1 && (addra_i == addrb_i)) begin + if((~(|wea) & |web) || wr_wr_col)begin + if (READ_LATENCY_A == 1) begin + force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + end + else begin + #1ps force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + end + end + else begin + release gen_rd_a.douta_reg; + end + end + else begin + release gen_rd_a.douta_reg; + end + end + end + end : gen_rd_a_coll + end : sync_clk_sym +//////////////////////////////////////////////////////////////////////////////////////////// +// code is for Common clock, Asymmetric case +//////////////////////////////////////////////////////////////////////////////////////////// + + if (`COMMON_CLOCK && `NO_ECC && ((WRITE_DATA_WIDTH_A != WRITE_DATA_WIDTH_B) || (WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) || (READ_DATA_WIDTH_A != WRITE_DATA_WIDTH_B))) begin : sync_clk_asym + reg wr_wr_col_asym = 0; + always @(ena or enb or wea or web or addra_i or addrb_i) begin + if (ena & enb) begin + if(|wea && |web) begin + if(WRITE_DATA_WIDTH_A > WRITE_DATA_WIDTH_B) begin + if (addra_i == addrb_i >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) + begin + wr_wr_col_asym <= 1'b1; + end + else begin + wr_wr_col_asym <= 1'b0; + end + end + else begin + if (addrb_i == addra_i >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) + begin + wr_wr_col_asym <= 1'b1; + end + else begin + wr_wr_col_asym <= 1'b0; + end + end + end + else begin + wr_wr_col_asym <= 1'b0; + end + end + else + wr_wr_col_asym <= 1'b0; + end + + // write-write collision modeling + // 1. check if both ports are writing and the address is equal + // 2. always allow the wider port to write to the memory + // 3. write enable of the narrower port has to be forced to 0 + // 4. assert the status signal to indicate wr-wr collision + // 5. check if both ports are writing same data + + always @(ena or enb or wea or web or addra_i or addrb_i) begin + if(ena & enb) begin + if(|wea && |web) begin + if(WRITE_DATA_WIDTH_A > WRITE_DATA_WIDTH_B) begin + if (addra_i == addrb_i >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) + force dina_i = {WRITE_DATA_WIDTH_A{1'bX}}; + else + release dina_i; + end + end + else + release dina_i; + end + else + release dina_i; + end + + always @(ena or enb or wea or web or addra_i or addrb_i) begin + if(ena & enb) begin + if(|wea && |web) begin + if(WRITE_DATA_WIDTH_A < WRITE_DATA_WIDTH_B) begin + if (addrb_i == addra_i >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) + force dinb_i = {WRITE_DATA_WIDTH_B{1'bX}}; + else + release dinb_i; + end + end + else + release dinb_i; + end + else + release dinb_i; + end + + always @(ena or enb or wea or web or addra_i or addrb_i) begin + if(ena & enb) begin + if(|wea && |web) begin + if(WRITE_DATA_WIDTH_A > WRITE_DATA_WIDTH_B) begin + if (addra_i == addrb_i >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) + force web_i = 'b0; + else + release web_i; + end + end + else + release web_i; + end + else + release web_i; + end + + always @(ena or enb or wea or web or addra_i or addrb_i) begin + if(ena & enb) begin + if(|wea && |web) begin + if(WRITE_DATA_WIDTH_A < WRITE_DATA_WIDTH_B) begin + if (addrb_i == addra_i >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) + force wea_i = 'b0; + else + release wea_i; + end + end + else + release wea_i; + end + else + release wea_i; + end + + if (`MEM_PORTB_READ && !(`IS_COLLISION_SAFE)) begin : gen_rd_b_coll + always @(posedge gen_rd_b.clkb_int) begin + if (enb == 1'b1) begin + if (ena == 1'b1) begin + if((|wea && ~(|web)) || wr_wr_col_asym) begin + if(WRITE_DATA_WIDTH_A > READ_DATA_WIDTH_B) begin + if (addra_i == addrb_i >> P_WIDTH_ADDR_READ_B-P_WIDTH_ADDR_WRITE_A) begin + if (READ_LATENCY_B == 1) + force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + else + #1ps force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + end + else + release gen_rd_b.doutb_reg; + end + else begin + if (addrb_i == addra_i >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_READ_B) begin + if (READ_LATENCY_B == 1) + force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + else + #1ps force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + end + else + release gen_rd_b.doutb_reg; + end + end + else + release gen_rd_b.doutb_reg; // write enable condition fails + end + else + release gen_rd_b.doutb_reg; // ena is 0 + end + end + end : gen_rd_b_coll + + if (`MEM_PORTA_READ && !(`IS_COLLISION_SAFE)) begin : gen_rd_a_coll + always @(posedge clka) begin + if (ena == 1'b1) begin + if (enb == 1'b1) begin + if((~(|wea) && |web) || wr_wr_col_asym) begin + if(READ_DATA_WIDTH_A > WRITE_DATA_WIDTH_B) begin + if (addra_i == addrb_i >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_READ_A) begin + if (READ_LATENCY_A == 1) + force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + else + #1ps force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + end + else + release gen_rd_a.douta_reg; + end + else begin + if (addrb_i == addra_i >> P_WIDTH_ADDR_READ_A-P_WIDTH_ADDR_WRITE_B) begin + if(READ_LATENCY_A == 1) + force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + else + #1ps force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + end + else + release gen_rd_a.douta_reg; + end + end + else + release gen_rd_a.douta_reg; + end + else + release gen_rd_a.douta_reg; + end + end + end : gen_rd_a_coll + +end : sync_clk_asym + +//////////////////////////////////////////////////////////////////////////////////////////// +// code is for Independant clock, symmetric case +//////////////////////////////////////////////////////////////////////////////////////////// + if (`INDEPENDENT_CLOCKS && (((WRITE_DATA_WIDTH_A == WRITE_DATA_WIDTH_B) && (WRITE_DATA_WIDTH_A == READ_DATA_WIDTH_B) && (READ_DATA_WIDTH_A == WRITE_DATA_WIDTH_B) && `NO_ECC) || !`NO_ECC)) begin : async_clk_sym + reg wr_wr_col_asym_a = 0; + reg wr_wr_col_asym_b = 0; + + always @(ena or enb or wea or web or addra_i or addrb_i or wra or wrb or addra_cap or addrb_cap or col_win_wr_b or col_win_wr_a or dinb_i or dina_i) + begin + if(enb == 1'b1) begin + if(wra == 1'b1 && addrb_i == addra_cap && col_win_wr_a) begin + if(|web) begin + force dinb_i = {WRITE_DATA_WIDTH_B{1'bX}}; + wr_wr_col_asym_b <= 1'b1; + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + always @(ena or enb or wea or web or addra_i or addrb_i or wra or wrb or addra_cap or addrb_cap or col_win_wr_b or col_win_wr_a or dinb_i or dina_i) + begin + if(ena == 1'b1) begin + if(wrb == 1'b1 && addra_i == addrb_cap && col_win_wr_b) begin + if(|wea) begin + force dina_i = {WRITE_DATA_WIDTH_A{1'bX}}; + wr_wr_col_asym_a <= 1'b1; + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + + if (`MEM_PORTB_READ && !(`IS_COLLISION_SAFE)) begin : gen_rd_b_coll + always @(posedge gen_rd_b.clkb_int) begin + if (enb == 1'b1) begin + if ( (wra == 1'b1 && addrb_i == addra_cap && ~(|web) && col_win_wr_a ) || (wr_wr_col_asym_a | wr_wr_col_asym_b)) begin + if(READ_LATENCY_B == 1) begin + force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + + end + else begin + #1ps force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + + end + end + else begin + release gen_rd_b.doutb_reg; + + end + end + end + end : gen_rd_b_coll + + if (`MEM_PORTA_READ && !(`IS_COLLISION_SAFE)) begin : gen_rd_a_coll + always @(posedge clka) begin + if (ena == 1'b1) begin + if ( ((wrb == 1'b1 && addra_i == addrb_cap && ~(|wea) && col_win_wr_b) || (wr_wr_col_asym_a | wr_wr_col_asym_b))) begin + if(READ_LATENCY_A == 1) + force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + else + #1ps force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + end + else + release gen_rd_a.douta_reg; + end + end + end : gen_rd_a_coll + + end : async_clk_sym + +//////////////////////////////////////////////////////////////////////////////////////////// +// code is for Independant clock, Asymmetric case +//////////////////////////////////////////////////////////////////////////////////////////// + + if (`INDEPENDENT_CLOCKS && `NO_ECC && ((WRITE_DATA_WIDTH_A != WRITE_DATA_WIDTH_B) && (WRITE_DATA_WIDTH_A != READ_DATA_WIDTH_B) && (READ_DATA_WIDTH_A != WRITE_DATA_WIDTH_B))) begin : async_clk_asym + reg wr_wr_col_asym_a = 0; + reg wr_wr_col_asym_b = 0; + + always @(ena or enb or wra or wrb or addra_i or addrb_i or addra_cap or addrb_cap or wea or web or col_win_wr_b or col_win_wr_a or dina_i or dinb_i) begin + if (ena == 1'b1) begin + if(wrb == 1'b1) begin + if(WRITE_DATA_WIDTH_A > WRITE_DATA_WIDTH_B) begin + if (addra_i == addrb_cap >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) begin + if(|wea && col_win_wr_b) begin + force dina_i = {WRITE_DATA_WIDTH_A{1'bX}}; + wr_wr_col_asym_a <= 1'b1; + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + else begin + if (addrb_cap == addra_i >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) begin + if(|wea && col_win_wr_b) begin + force dina_i = {WRITE_DATA_WIDTH_A{1'bX}}; + wr_wr_col_asym_a <= 1'b1; + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + else begin + release dina_i; + wr_wr_col_asym_a <= 1'b0; + end + end + + always @(ena or enb or wra or wrb or addra_i or addrb_i or addra_cap or addrb_cap or wea or web or col_win_wr_b or col_win_wr_a or dina_i or dinb_i) begin + if (enb == 1'b1) begin + if(wra == 1'b1) begin + if(WRITE_DATA_WIDTH_A > WRITE_DATA_WIDTH_B) begin + if (addra_cap == addrb_i >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_WRITE_A) begin + if(|web && col_win_wr_a) begin + force dinb_i = {WRITE_DATA_WIDTH_B{1'bX}}; + wr_wr_col_asym_b <= 1'b1; + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + else begin + if (addrb_i == addra_cap >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_WRITE_B) begin + if(|web && col_win_wr_a) begin + force dinb_i = {WRITE_DATA_WIDTH_B{1'bX}}; + wr_wr_col_asym_b <= 1'b1; + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + else begin + release dinb_i; + wr_wr_col_asym_b <= 1'b0; + end + end + +// As Assymetry Internal to port is not allowed, Limiting the comparision to +// across ports (WRITE_DATA_WIDTH_A = READ_DATA_WIDTH_A and READ_DATA_WIDTH_B = WRITE_DATA_WIDTH_B) + if (`MEM_PORTA_READ && !(`IS_COLLISION_SAFE)) begin : gen_rd_a_coll + always @(posedge clka) begin + if (ena == 1'b1 ) begin + if(wrb == 1'b1 && ~(|wea)) begin + if(READ_DATA_WIDTH_A > WRITE_DATA_WIDTH_B) begin + if ((addra_i == addrb_cap >> P_WIDTH_ADDR_WRITE_B-P_WIDTH_ADDR_READ_A && col_win_wr_b) || (wr_wr_col_asym_a | wr_wr_col_asym_b)) begin + if (READ_LATENCY_A == 1) + force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + else + #1ps force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + end + else + release gen_rd_a.douta_reg; + end + else begin + if ((addrb_cap == addra_i >> P_WIDTH_ADDR_READ_A-P_WIDTH_ADDR_WRITE_B && col_win_wr_b) || (wr_wr_col_asym_a | wr_wr_col_asym_b)) begin + if (READ_LATENCY_A == 1) + force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + else + #1ps force gen_rd_a.douta_reg = {READ_DATA_WIDTH_A{1'bX}}; + end + else + release gen_rd_a.douta_reg; + end + end + else + release gen_rd_a.douta_reg; + end + end + end : gen_rd_a_coll + + if (`MEM_PORTB_READ && !(`IS_COLLISION_SAFE)) begin : gen_rd_b_coll + always @(posedge clkb) begin + if (enb == 1'b1) begin + if( wra == 1'b1 && ~(|web) ) begin + if(WRITE_DATA_WIDTH_A > READ_DATA_WIDTH_B) begin + if ((addra_cap == addrb_i >> P_WIDTH_ADDR_READ_B-P_WIDTH_ADDR_WRITE_A && col_win_wr_a) || (wr_wr_col_asym_a | wr_wr_col_asym_b)) begin + if(READ_LATENCY_B == 1) + force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + else + #1ps force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + end + else + release gen_rd_b.doutb_reg; + end + else begin + if ((addrb_i == addra_cap >> P_WIDTH_ADDR_WRITE_A-P_WIDTH_ADDR_READ_B && col_win_wr_a) || (wr_wr_col_asym_a | wr_wr_col_asym_b)) begin + if(READ_LATENCY_B == 1) + force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + else + #1ps force gen_rd_b.doutb_reg = {READ_DATA_WIDTH_B{1'bX}}; + end + else + release gen_rd_b.doutb_reg; + end + end + else + release gen_rd_b.doutb_reg; + end + end + end : gen_rd_b_coll + end : async_clk_asym +end : gen_assert_coll_ww + +`endif + +// Sleep Mode behaviour Model + +if (`SLEEP_MODE && !`MEM_AUTO_SLP_EN) begin : gen_dyn_power_saving_mode + +//////////////////////////////////////////////////////////////////////////////// + // Wakeup_time modeling // + // SLEEP --- 2 clocks // +//////////////////////////////////////////////////////////////////////////////// + + reg [9:0] sleep_edg_det_a; + wire de_activate_slp_mode_a; //falling edge of sleep port + wakeup_time w.r.to Port-A clock + +// Initialize the variables + initial begin + sleep_edg_det_a = 'b0; + sleep_int_a = 1'b0; + end +// Shift register to continuously monitor the transitions on sleep port + always @(posedge clka) begin : sleep_sync_clka + sleep_edg_det_a <= {sleep_edg_det_a[8:0],sleep}; + end : sleep_sync_clka + +// Sleep Falling edge detection + if (`SLEEP_MODE) + assign de_activate_slp_mode_a = (sleep_edg_det_a[2:0] == 3'b100)? 1'b1 : 1'b0; + else + assign de_activate_slp_mode_a = 1'b1; + +// Generate the Active sleep duration including the wake up time + always @(*) + begin + if(sleep == 1'b1) + sleep_int_a = 1'b1; + else if(de_activate_slp_mode_a == 1'b1) + #2 sleep_int_a = 1'b0; + end + +// Check if port-A write is allowed +if (`MEM_PORTA_WRITE ) begin : gen_dyn_pwr_save_wr_a + // ignore write operation during sleep mode + always @(sleep_int_a or sleep_int_b) + begin : proc_force_dina + if (sleep_int_a == 1'b1 || sleep_int_b == 1'b1) + force mem = mem; // mem array is un-changed + else + release mem; + end : proc_force_dina + // Assertion to detect the write operation during sleep mode + assert property (@(posedge clka) + ~(sleep_int_a === 1'b1 && ena === 1'b1 && |wea)) + else + $warning("WRITE on Port A attempted while in SLEEP mode at time %t", $time); +end : gen_dyn_pwr_save_wr_a + +// Check if Read on Port-A is allowed +if (`MEM_PORTA_READ ) begin : gen_dyn_pwr_save_rd_a + // Assertion to detect the read operation during sleep mode + assert property (@(posedge clka) + ~(sleep_int_a === 1'b1 && ena === 1'b1 && ~(|wea) )) + else + $warning("READ on Port A attempted while in SLEEP mode at time %t", $time); + +// When in Latch Mode + if (`MEM_PORTA_RD_REG) begin : gen_sleep_a_latch_mode + always @(posedge clka) begin : pwr_sav_mode_rd_det_a + if (sleep_int_a == 1'b1 || sleep_int_b == 1'b1) begin + if (ena == 1'b1 ) begin + if (`MEM_PORTA_WF) begin + if(|wea) + force douta = {READ_DATA_WIDTH_A{1'bx}}; + else + force douta = {READ_DATA_WIDTH_A{1'bx}}; end + else if (`MEM_PORTA_RF) + force douta = {READ_DATA_WIDTH_A{1'bx}}; + else begin + if(|wea) + force douta = douta; + else + force douta = {READ_DATA_WIDTH_A{1'bx}}; + end + end + end + else begin + if(`MEM_PORTA_NC) begin + if(~(|wea) & ena) + release douta; + end + else begin + if(ena) + release douta; + end + end + end : pwr_sav_mode_rd_det_a + end : gen_sleep_a_latch_mode + +// If pipe line stages are enabled + if (`MEM_PORTA_RD_PIPE) begin : gen_sleep_a_reg_mode + reg ena_pipe_sleep [READ_LATENCY_A-2:0]; + reg ena_pipe_dup [READ_LATENCY_A-2:0]; + reg wea_pipe_sleep [READ_LATENCY_A-2:0]; + reg wea_pipe_dup [READ_LATENCY_A-2:0]; + // Capture the READ operations during and after sleep modes + always @(posedge clka) begin + if(sleep_int_a == 1'b1 || sleep_int_b == 1'b1) begin + ena_pipe_sleep[0] <= ena; // Capture all READ operations during sleep + ena_pipe_dup[0] <= 1'b0; + wea_pipe_sleep[0] <= |wea; // Capture all WRITE operations during sleep + wea_pipe_dup[0] <= 1'b0; + end + else begin + ena_pipe_sleep[0] <= 1'b0; + ena_pipe_dup[0] <= ena; // Capture All valid READ Operations + wea_pipe_sleep[0] <= 1'b0; + wea_pipe_dup[0] <= |wea; // Capture All valid WRITE Operations + end + end + + // If more than two stages are used, loops generate all pipeline stages except the first and last + if (READ_LATENCY_A > 2) begin : porta_slp_gen_estages + for (genvar slp_estage=1; slp_estage 2 + // Force DOUT depending on the latency and the WRITE_MODE + if ( READ_LATENCY_A >= 2) begin : gen_sleep_porta_highr_Latncy + always @(posedge clka) begin : sleep_porta_rd_highr_Latncy_force + if (last_pipe_en_ctrl_a && regcea) begin + if (`MEM_PORTA_WF) begin + force douta = {READ_DATA_WIDTH_A{1'bx}}; + end + else if (`MEM_PORTA_RF) + force douta = {READ_DATA_WIDTH_A{1'bx}}; + else begin + if(rda_happened) + force douta = {READ_DATA_WIDTH_A{1'bx}}; + else if(ena_pipe_sleep[READ_LATENCY_A-2] & wea_pipe_sleep[READ_LATENCY_A-2]) + force douta = douta; + end + end + end : sleep_porta_rd_highr_Latncy_force + + always @(posedge clka) begin : sleep_porta_rd_highr_Latncy_release + if(~last_pipe_en_ctrl_a) begin + // when all the reads of sleep are over, check if there is a + // valid regcea and pipe lined enable (not sleep enable) + if (rsta) release douta; + else begin + if (regcea) begin + if(`MEM_PORTA_NC) begin + if(!wea_pipe_dup[READ_LATENCY_A-2] && ena_pipe_dup[READ_LATENCY_A-2]) + release douta; + end + else // not No_change + release douta; + end // release when there is a valid READ + end + end + end : sleep_porta_rd_highr_Latncy_release + end : gen_sleep_porta_highr_Latncy + end : gen_sleep_a_reg_mode +end : gen_dyn_pwr_save_rd_a + +if (`MEM_PORTB_READ ) begin : gen_dyn_pwr_save_b +// Internal Signal Declarations + reg [9:0] sleep_edg_det_b; + reg de_activate_slp_mode_b; //falling edge of sleep port + wakeup_time w.r.to Port-B clock + +// Initialize all the internal signals + initial begin + sleep_int_b = 1'b0; + sleep_edg_det_b = 'b0; + end + + //Effective Sleep Mode Duration identification + always @(posedge gen_rd_b.clkb_int) + begin : sleep_sync_clkb + sleep_edg_det_b <= {sleep_edg_det_b[8:0],sleep}; + end : sleep_sync_clkb + + if (`SLEEP_MODE) + assign de_activate_slp_mode_b = (sleep_edg_det_b[2:0] == 3'b100)? 1'b1 : 1'b0; + else + assign de_activate_slp_mode_b = 1'b1; + + always @(*) + begin + if(sleep == 1'b1) + sleep_int_b = 1'b1; + else if(de_activate_slp_mode_b == 1'b1) + #2 sleep_int_b = 1'b0; + end + +// Check if Port-B write is allowed + if (`MEM_PORTB_WRITE ) begin : gen_dyn_pwr_save_wr_b + // Assertions to detect the READ and WRITE operations during sleep mode + assert property (@(posedge gen_rd_b.clkb_int) + ~(sleep_int_b === 1'b1 && enb === 1'b1 && |web)) + else + $warning("WRITE on Port B attempted while in SLEEP mode at time %t", $time); + end : gen_dyn_pwr_save_wr_b + + assert property (@(posedge gen_rd_b.clkb_int) + ~(sleep_int_b === 1'b1 && enb === 1'b1 && ~(|web))) + else + $warning("READ on Port B attempted while in SLEEP mode at time %t", $time); +// Forcing DOUTB when in latch mode + if (`MEM_PORTB_RD_REG) begin : gen_sleep_b_latch_mode + + always @(posedge gen_rd_b.clkb_int) begin : pwr_sav_mode_rd_det_b + if (sleep_int_a == 1'b1 || sleep_int_b == 1'b1) begin + if (enb == 1'b1 ) begin + if (`MEM_PORTB_WF) begin + if(|web) + force doutb = {READ_DATA_WIDTH_B{1'bx}}; + else + force doutb = {READ_DATA_WIDTH_B{1'bx}}; end + else if (`MEM_PORTB_RF) + force doutb = {READ_DATA_WIDTH_B{1'bx}}; + else begin + if(|web) + force doutb = doutb; + else + force doutb = {READ_DATA_WIDTH_B{1'bx}}; + end + end + end + else begin + if(`MEM_PORTB_NC) begin + if(~(|web) & enb) + release doutb; + end + else begin + if(enb) + release doutb; + end + end + end : pwr_sav_mode_rd_det_b + end : gen_sleep_b_latch_mode + + if (`MEM_PORTB_RD_PIPE) begin : gen_sleep_b_reg_mode + // Internal Signal Declaration + reg enb_pipe_sleep [READ_LATENCY_B-2:0]; + reg enb_pipe_dup [READ_LATENCY_B-2:0]; + reg web_pipe_sleep [READ_LATENCY_B-2:0]; + reg web_pipe_dup [READ_LATENCY_B-2:0]; + + always @(posedge gen_rd_b.clkb_int) begin + if(sleep_int_a === 1'b1 || sleep_int_b === 1'b1) + begin + enb_pipe_sleep[0] <= enb; // Capture all READ operations during sleep + enb_pipe_dup[0] <= 1'b0; + web_pipe_sleep[0] <= |web; // Capture all WRITE operations during sleep + web_pipe_dup[0] <= 1'b0; + end + else + begin + enb_pipe_sleep[0] <= 1'b0; + enb_pipe_dup[0] <= enb; // Capture All valid READ Operations + web_pipe_sleep[0] <= 1'b0; + web_pipe_dup[0] <= |web; // Capture All valid WRITE Operations + end + end + + // If more than two stages are used, loops generate all pipeline stages except the first and last + if (READ_LATENCY_B > 2) begin : portb_slp_gen_estages + for (genvar portb_slp_estage=1; portb_slp_estage= 2) begin : gen_sleep_portb_highr_Latncy + always @(posedge gen_rd_b.clkb_int) begin : sleep_portb_rd_highr_Latncy_force + if(last_pipe_en_ctrl_b && regceb) begin + if (`MEM_PORTB_WF) begin + force doutb = {READ_DATA_WIDTH_B{1'bx}}; + end + else if (`MEM_PORTB_RF) + force doutb = {READ_DATA_WIDTH_B{1'bx}}; + else begin + if(rdb_happened) + force doutb = {READ_DATA_WIDTH_B{1'bx}}; + else if(enb_pipe_sleep[READ_LATENCY_B-2] & web_pipe_sleep[READ_LATENCY_B-2]) + force doutb = doutb; + end + end + end : sleep_portb_rd_highr_Latncy_force + + always @(posedge gen_rd_b.clkb_int) begin : sleep_portb_rd_highr_Latncy_release + if (~last_pipe_en_ctrl_b) begin + // when all the reads of sleep are over, check if there is a + // valid regceb and pipe lined enable (not sleep enable) + if (rstb) release doutb; + else begin + if (regceb) begin + if(`MEM_PORTB_NC) begin + if(!web_pipe_dup[READ_LATENCY_B-2] && enb_pipe_dup[READ_LATENCY_B-2]) + release doutb; + end + else // not No_change + release doutb; + end // release when there is a valid READ + end + end + end : sleep_portb_rd_highr_Latncy_release + end : gen_sleep_portb_highr_Latncy + end : gen_sleep_b_reg_mode +end : gen_dyn_pwr_save_b + +end : gen_dyn_power_saving_mode + + if(`MEM_AUTO_SLP_EN) begin : gen_auto_slp_dly_sim + reg [ADDR_WIDTH_A-1:0] addra_aslp_pipe_sim [AUTO_SLEEP_TIME-1:0]; + reg [ADDR_WIDTH_B-1:0] addrb_aslp_pipe_sim [AUTO_SLEEP_TIME-1:0]; + // Initialize the address pipeline + initial begin + integer initstage_a; + integer initstage_b; + for (initstage_a=0; initstage_a P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during sleep mode and the address being out of range.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && sleep && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during sleep mode and the address being out of range.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && sleep && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during sleep mode and the address being out of range.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && sleep && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during sleep mode and the address being out of range.", addrb, $time); + + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && rsta && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during reset and the address being out of range.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && rsta && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during reset and the address being out of range.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && rstb && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during reset and the address being out of range.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && rstb && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during reset and the address being out of range.", addrb, $time); + + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && sleep && rsta && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during sleep mode with reset asserted and the address being out of range.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && sleep && rsta && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during sleep mode with reset asserted and the address being out of range.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && sleep && rstb && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during sleep mode with reset asserted and the address being out of range.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && sleep && rstb && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in both Encode and Decode mode configuration during sleep mode with reset asserted and the address being out of range.", addrb, $time); + end : chk_vld_ecc_both_configs + + if(`ENC_ONLY) begin : chk_vld_ecc_enc_only_configs + // checks to see if error injection is covered + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration.", addrb, $time); + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && injectdbiterra && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_BOTH_ERR_INJ_ASSRT: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && injectdbiterrb && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_BOTH_ERR_INJ_ASSRT: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration.", addrb, $time); + + + // checks to see if error injection is covered during reset + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && rsta && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_RST_ASSRT: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during reset.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && rsta && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_RST_ASSRT: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during reset.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && rstb && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_RST_ASSRT: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during reset.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && rstb && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_RST_ASSRT: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during reset.", addrb, $time); + + // Check if sleep port is asserted on both port-a and port-b + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && sleep && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && sleep && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && sleep && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && sleep && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode.", addrb, $time); + + // checks to see if error injection is covered during sleep & reset + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && sleep && rsta && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode with reset asserted.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && sleep && rsta && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode with reset asserted.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && sleep && rstb && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode with reset asserted.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && sleep && rstb && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode with reset asserted.", addrb, $time); + + // Check if out-of range addresses are driven + // Check if the error injection is happening + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && sleep && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode and the address being out of range.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && sleep && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode and the address being out of range.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && sleep && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode and the address being out of range.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && sleep && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode and the address being out of range.", addrb, $time); + + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && rsta && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during reset and the address being out of range.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && rsta && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during reset and the address being out of range.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && rstb && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during reset and the address being out of range.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && rstb && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during reset and the address being out of range.", addrb, $time); + + assert property (@(posedge clka) + !(ena && |wea && injectsbiterra && sleep && rsta && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode with reset asserted and the address being out of range.", addra, $time); + assert property (@(posedge clka) + !(ena && |wea && injectdbiterra && sleep && rsta && addra > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-A at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode with reset asserted and the address being out of range.", addra, $time); + assert property (@(posedge clkb) + !(enb && |web && injectsbiterrb && sleep && rstb && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_INJ_ASSRT_SLEEP: single bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode with reset asserted and the address being out of range.", addrb, $time); + assert property (@(posedge clkb) + !(enb && |web && injectdbiterrb && sleep && rstb && addrb > P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_INJ_ASSRT_SLEEP: double bit error into the memory through Port-B at address 0x%0h at time %0t happened in encode only mode configuration during sleep mode with reset asserted and the address being out of range.", addrb, $time); + end : chk_vld_ecc_enc_only_configs + + if(`DEC_ONLY) begin : chk_vld_ecc_dec_only_configs + // Decode only mode Checks + assert property (@(posedge clka) + !(sbiterra_int && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_STATUS: single bit error asserted through Port-A at address 0x%0h at time %0t in decode only mode configuration", addra, $time); + assert property (@(posedge clka) + !(dbiterra_int && addra <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_STATUS: single bit error asserted through Port-A at address 0x%0h at time %0t in decode only mode configuration", addra, $time); + assert property (@(posedge clkb) + !(sbiterrb_int && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_SINGLE_BIT_ERR_STATUS: single bit error asserted through Port-B at address 0x%0h at time %0t in decode only mode configuration", addrb, $time); + assert property (@(posedge clkb) + !(dbiterrb_int && addrb <= P_MAX_DEPTH_DATA)) + else + $info("XPM_MEMORY_DOUBLE_BIT_ERR_STATUS: single bit error asserted through Port-B at address 0x%0h at time %0t in decode only mode configuration", addrb, $time); + end : chk_vld_ecc_dec_only_configs + + // Check if there is a collision that happened during ECC mode w.r.t + // data and error status ports + end : ecc_cover + `endif + `endif + + function [P_MIN_WIDTH_PARITY_ECC-1:0] ecc_init_mem_loc; + input [WRITE_DATA_WIDTH_A-1 : 0] data_in; + integer data_slice; + for (data_slice=1; data_slice <= WRITE_DATA_WIDTH_A/64; data_slice=data_slice+1) begin + //ecc_init_mem_loc[(72*data_slice)-9 : (72*data_slice)-72] = data_in[(64*data_slice)-1 : (data_slice-1)*64]; + ecc_init_mem_loc[(72*data_slice)-9 -: 64] = data_in[(64*data_slice)-1 -: 64]; + ecc_init_mem_loc[(72*data_slice)-1 -: 8] = fn_ecc_enc_dec(1'b1, data_in[(64*data_slice)-1 -: 64], 8'h00); + end + endfunction + + // Memory Array Initialization + initial begin + if (`NO_MEMORY_INIT) begin : init_zeroes + integer ecc_initword; + for (ecc_initword=0; ecc_initword= P_MAX_DEPTH_DATA)) begin + if(ena_i & ~(|wea_i)) begin + sbiterra_int <= 1'bX; + dbiterra_int <= 1'bX; + end + end + else if (rsta && READ_LATENCY_A ==1) begin + sbiterra_int <= 1'b0; + dbiterra_int <= 1'b0; + end + else if(ena_i) begin + if(~(|wea_i)) begin + if (sbiterr_status[addra_i] == 1'b1) + sbiterra_int <= 1'b1; + else + sbiterra_int <= 1'b0; + if (dbiterr_status[addra_i] == 1'b1) + dbiterra_int <= 1'b1; + else + dbiterra_int <= 1'b0; + end + end + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.sbiterra_in_pipe = sbiterra_int & ~dbiterra_int; + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.dbiterra_in_pipe = dbiterra_int; + end : erra_status + always @(posedge clka) begin + if(rsta && READ_LATENCY_A ==1) + deassign gen_rd_a.douta_reg; + else begin + if(addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(ena_i && ~(|wea_i) && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1))) begin + douta_int <= mem_ecc[addra_i]; + assign gen_rd_a.douta_reg = douta_int; + end + end + else begin + douta_int <= 'bX; + assign gen_rd_a.douta_reg = douta_int; + end + end + end + end : nc_prta + if (`MEM_PORTA_RF) begin : rf_prta + always @(posedge clka) begin: erra_status + if (sleep_int_a || sleep_int_b == 1'b1 || (addra_aslp_sim >= P_MAX_DEPTH_DATA)) begin + if(ena_i) begin + sbiterra_int <= 1'bX; + dbiterra_int <= 1'bX; + end + end + else if (rsta && READ_LATENCY_A ==1) begin + sbiterra_int <= 1'b0; + dbiterra_int <= 1'b0; + end + else if(ena_i) begin + if (sbiterr_status[addra_i] == 1'b1) + sbiterra_int <= 1'b1; + else + sbiterra_int <= 1'b0; + if (dbiterr_status[addra_i] == 1'b1) + dbiterra_int <= 1'b1; + else + dbiterra_int <= 1'b0; + end + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.sbiterra_in_pipe = sbiterra_int & ~dbiterra_int; + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.dbiterra_in_pipe = dbiterra_int; + end : erra_status + always @(posedge clka) begin + if(rsta && READ_LATENCY_A ==1) + deassign gen_rd_a.douta_reg; + else begin + if(addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1))) begin + douta_int <= mem_ecc[addra_i]; + assign gen_rd_a.douta_reg = douta_int; + end + end + else begin + douta_int <= 'bX; + assign gen_rd_a.douta_reg = douta_int; + end + end + end + end : rf_prta + + if (`MEM_PORTA_WF) begin : wf_porta + always @(posedge clka) begin: erra_status + if (sleep_int_a || sleep_int_b == 1'b1 || (addra_aslp_sim >= P_MAX_DEPTH_DATA)) begin + if(ena_i) begin + sbiterra_int <= 1'bX; + dbiterra_int <= 1'bX; + end + end + else if (rsta && READ_LATENCY_A ==1) begin + sbiterra_int <= 1'b0; + dbiterra_int <= 1'b0; + end + else if(ena_i) begin + if(|wea_i) begin + if(injectsbiterra_sim) + sbiterra_int <= 1'b1; + else + sbiterra_int <= 1'b0; + if(injectdbiterra_sim) + dbiterra_int <= 1'b1; + else + dbiterra_int <= 1'b0; + end + else begin + if (sbiterr_status[addra_i] == 1'b1) + sbiterra_int <= 1'b1; + else + sbiterra_int <= 1'b0; + if (dbiterr_status[addra_i] == 1'b1) + dbiterra_int <= 1'b1; + else + dbiterra_int <= 1'b0; + end + end + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.sbiterra_in_pipe = sbiterra_int & ~dbiterra_int; + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.dbiterra_in_pipe = dbiterra_int; + end : erra_status + for (genvar data_slice_a=1; data_slice_a <= WRITE_DATA_WIDTH_A/64; data_slice_a=data_slice_a+1) begin : ecc_data_calc_a + always @(*) begin : ecc_enc_only_data_wr + if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1)) && addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(|wea_i) begin + if(injectdbiterra_sim) + din_to_mem_ecc_a[(64*data_slice_a)-1 : (data_slice_a-1)*64] = {dina_i[(64*data_slice_a)-1],~dina_i[(64*data_slice_a)-2] ,dina_i[(64*data_slice_a)-3 : (64*data_slice_a)-33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 : (data_slice_a-1)*64]}; + end + end + end : ecc_enc_only_data_wr + end : ecc_data_calc_a + + always @(posedge clka) begin + if(rsta && READ_LATENCY_A ==1) + deassign gen_rd_a.douta_reg; + else begin + if(addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1))) begin + if(|wea_i) begin + if (injectdbiterra_sim) + douta_int <= din_to_mem_ecc_a; + else + douta_int <= dina_i; + end + else + douta_int <= mem_ecc[addra_i]; + assign gen_rd_a.douta_reg = douta_int; + end + end + else begin + douta_int <= 'bX; + assign gen_rd_a.douta_reg = douta_int; + end + end + end + end : wf_porta + end : nc_rf_wf_porta + if (`MEM_PORTB_READ) begin : dbiterrb_data_gen_proc + // Only No_Change mode behavior is considered, as TDP + URAM supports + // no_change mode. This will work for BRAM as only SDP mode is supported + always @(posedge gen_rd_b.clkb_int) begin: sbiterrb_gen_proc + if (sleep_int_a == 1'b1 || sleep_int_b == 1'b1 || (addrb_aslp_sim >= P_MAX_DEPTH_DATA)) begin + if (enb_i & ~(|web_i)) begin + sbiterrb_int <= 1'bX; + dbiterrb_int <= 1'bX; + end + end + else if (rstb && READ_LATENCY_B ==1) begin + sbiterrb_int <= 1'b0; + dbiterrb_int <= 1'b0; + end + else if(enb_i & ~(|web_i)) begin + if(`MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP) begin + if (ena_i && |wea_i && (addra_i == addrb_i) && addrb_aslp_sim < P_MAX_DEPTH_DATA) begin + if(injectsbiterra_sim) + sbiterrb_int <= 1'b1; + else + sbiterrb_int <= 1'b0; + if(injectdbiterra_sim) + dbiterrb_int <= 1'b1; + else + dbiterrb_int <= 1'b0; + end + else begin + if (sbiterr_status[addrb_i] == 1'b1) + sbiterrb_int <= 1'b1; + else + sbiterrb_int <= 1'b0; + if (dbiterr_status[addrb_i] == 1'b1) + dbiterrb_int <= 1'b1; + else + dbiterrb_int <= 1'b0; + end + end + else begin + if (sbiterr_status[addrb_i] == 1'b1) + sbiterrb_int <= 1'b1; + else + sbiterrb_int <= 1'b0; + if (dbiterr_status[addrb_i] == 1'b1) + dbiterrb_int <= 1'b1; + else + dbiterrb_int <= 1'b0; + end + end + assign gen_rd_b.pipeline_ecc_status.sbiterrb_in_pipe = sbiterrb_int & ~dbiterrb_int; + assign gen_rd_b.pipeline_ecc_status.dbiterrb_in_pipe = dbiterrb_int; + end : sbiterrb_gen_proc + + if(`MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP) begin : tdp_ultra_wf_gen + for (genvar data_slice_a=1; data_slice_a <= WRITE_DATA_WIDTH_A/64; data_slice_a=data_slice_a+1) begin : ecc_data_calc_a + always @(*) begin : ecc_enc_only_data_wr + if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1)) && addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(|wea_i) begin + if(injectdbiterra_sim) + din_to_mem_ecc_a_tdp_ultra[(64*data_slice_a)-1 : (data_slice_a-1)*64] = {dina_i[(64*data_slice_a)-1],~dina_i[(64*data_slice_a)-2] ,dina_i[(64*data_slice_a)-3 : (64*data_slice_a)-33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 : (data_slice_a-1)*64]}; + end + end + end : ecc_enc_only_data_wr + end : ecc_data_calc_a + end : tdp_ultra_wf_gen + + always @(posedge gen_rd_b.clkb_int) begin + if (rstb && READ_LATENCY_B == 1) + deassign gen_rd_b.doutb_reg; + else begin + if(addrb_aslp_sim < P_MAX_DEPTH_DATA) begin + if(enb_i & ~(|web_i) && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1))) begin + // If A is writing and B is reading then it should read the new data + if(`MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP) begin + if (ena_i && |wea_i && (addra_i == addrb_i) && addrb_aslp_sim < P_MAX_DEPTH_DATA) begin + if(injectdbiterra_sim) begin + doutb_int <= din_to_mem_ecc_a_tdp_ultra; + assign gen_rd_b.doutb_reg = doutb_int; + end + else begin + doutb_int <= dina_i; + assign gen_rd_b.doutb_reg = doutb_int; + end + end + else begin + doutb_int <= mem_ecc[addrb_i]; + assign gen_rd_b.doutb_reg = doutb_int; + end + end + else begin + doutb_int <= mem_ecc[addrb_i]; + assign gen_rd_b.doutb_reg = doutb_int; + end + end + end + else begin + doutb_int <= 'bX; + assign gen_rd_b.doutb_reg = doutb_int; + end + end + end + end : dbiterrb_data_gen_proc + end : en_enc_dec + // ------------------------------------------------------------------------------------------------------------------- + /**ECC Behavioral Modeling when Encoder only is enabled + This module need to perform the parity calculations on the data and write to the memroy + This module needs to model the Error Injection, corrupt the data and + write to the memory + Error status signals can never get asserted here + **/ + // ------------------------------------------------------------------------------------------------------------------- + + + if (ECC_MODE == 1 || (ECC_MODE == 3 && !(`NO_MEMORY_INIT))) begin : en_enc_only + + // memory declaration (aspect ratio is not supported when ECC Enabled) + // Actual Template needs to be supplied by synthesis team + + + reg [0:0] sbiterr_status [0:P_MAX_DEPTH_DATA-1]; + reg [0:0] dbiterr_status [0:P_MAX_DEPTH_DATA-1]; + + // Data is expected to be in the multiples of 64-bits + // Data - parity calculation can be continuously calculated + + // The Implementation involves in 3 steps : + // 1. Memory Array in this case needs to be created with the width being + // multiple of 72 bits + // 2. Calculate the width of the vector comprising of data and parity + // 3. Have a generate statement to calculate the parity and assign to the + // din_to_mem_ecc vector + // 4. Have a generate statement to assign the data input to the proper + // segments of the din_to_mem_ecc vector + // 5. Assign the complete constructed data array to the memory + + // Error Injection Implementation + // Memory needs to be corrupted for both Single and Double bit Error + // injection transactions here + + for (genvar data_slice_a=1; data_slice_a <= WRITE_DATA_WIDTH_A/64; data_slice_a=data_slice_a+1) begin : ecc_data_calc_a + always @(posedge clka) begin : ecc_enc_only_data_wr + if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1)) && addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(`MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP) begin + if (!(enb_i && |web_i && addrb_i == addra_i)) begin + if(|wea_i) begin + if(injectdbiterra_sim) + mem_ecc[addra_i][(72*data_slice_a)-9 : (72*data_slice_a)-72] <= {dina_i[(64*data_slice_a)-1],~dina_i[(64*data_slice_a)-2] ,dina_i[(64*data_slice_a)-3 : (64*data_slice_a)-33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 : (data_slice_a-1)*64]}; + else if(injectsbiterra_sim) + mem_ecc[addra_i][(72*data_slice_a)-9 : (72*data_slice_a)-72] <= {dina_i[(64*data_slice_a)-1 : (64*data_slice_a)-33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 : (data_slice_a-1)*64]}; + else + mem_ecc[addra_i][(72*data_slice_a)-9 : (72*data_slice_a)-72] <= dina_i[(64*data_slice_a)-1 : (data_slice_a-1)*64]; + mem_ecc[addra_i][(72*data_slice_a)-1 : (72*data_slice_a)-8] <= fn_ecc_enc_dec(1'b1, dina_i[(64*data_slice_a)-1 : (data_slice_a-1)*64], 8'h00); + end + end + end + else begin + if(|wea_i) begin + if(injectdbiterra_sim) + mem_ecc[addra_i][(72*data_slice_a)-9 : (72*data_slice_a)-72] <= {dina_i[(64*data_slice_a)-1],~dina_i[(64*data_slice_a)-2] ,dina_i[(64*data_slice_a)-3 : (64*data_slice_a)-33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 : (data_slice_a-1)*64]}; + else if(injectsbiterra_sim) + mem_ecc[addra_i][(72*data_slice_a)-9 : (72*data_slice_a)-72] <= {dina_i[(64*data_slice_a)-1 : (64*data_slice_a)-33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 : (data_slice_a-1)*64]}; + else + mem_ecc[addra_i][(72*data_slice_a)-9 : (72*data_slice_a)-72] <= dina_i[(64*data_slice_a)-1 : (data_slice_a-1)*64]; + mem_ecc[addra_i][(72*data_slice_a)-1 : (72*data_slice_a)-8] <= fn_ecc_enc_dec(1'b1, dina_i[(64*data_slice_a)-1 : (data_slice_a-1)*64], 8'h00); + end + end + end + end : ecc_enc_only_data_wr + end : ecc_data_calc_a + + if (`MEM_PORTB_WRITE && (`MEM_PRIM_ULTRA || `MEM_PRIM_AUTO)) begin : data_in_proc_b + for (genvar data_slice_b=1; data_slice_b <= WRITE_DATA_WIDTH_B/64; data_slice_b=data_slice_b+1) begin : ecc_data_calc_b + always @(posedge gen_wr_b.clkb_int) begin : ecc_enc_only_data_wr_b + if(enb_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1)) && addrb_aslp_sim < P_MAX_DEPTH_DATA) begin + if(|web_i) begin + if(injectdbiterrb_sim) + mem_ecc[addrb_i][(72*data_slice_b)-9 : (72*data_slice_b)-72] <= {dinb_i[(64*data_slice_b)-1],~dinb_i[(64*data_slice_b)-2] ,dinb_i[(64*data_slice_b)-3 : (64*data_slice_b)-33],~dinb_i[(64*data_slice_b)-34],dinb_i[(64*data_slice_b)-35 : (data_slice_b-1)*64]}; + else if(injectsbiterrb_sim) + mem_ecc[addrb_i][(72*data_slice_b)-9 : (72*data_slice_b)-72] <= {dinb_i[(64*data_slice_b)-1 : (64*data_slice_b)-33],~dinb_i[(64*data_slice_b)-34],dinb_i[(64*data_slice_b)-35 : (data_slice_b-1)*64]}; + else + mem_ecc[addrb_i][(72*data_slice_b)-9 : (72*data_slice_b)-72] <= dinb_i[(64*data_slice_b)-1 : (data_slice_b-1)*64]; + mem_ecc[addrb_i][(72*data_slice_b)-1 : (72*data_slice_b)-8] <= fn_ecc_enc_dec(1'b1, dinb_i[(64*data_slice_b)-1 : (data_slice_b-1)*64], 8'h00); + end + end + end : ecc_enc_only_data_wr_b + end : ecc_data_calc_b + end : data_in_proc_b + if (ECC_MODE == 1 && `MEM_PORTB_READ) begin : data_enc_only + always @(posedge gen_rd_b.clkb_int) begin: data_out_proc_b + if (rstb && READ_LATENCY_B == 1) + deassign gen_rd_b.doutb_reg; + else if(enb_i && ~(|web_i) && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1))) begin + if(`MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP) begin + if (ena_i && |wea_i && (addra_i == addrb_i) && addrb_aslp_sim < P_MAX_DEPTH_DATA) begin + if(injectdbiterra_sim) begin + for (integer data_slice_a=1; data_slice_a <= WRITE_DATA_WIDTH_A/64; data_slice_a=data_slice_a+1) begin + din_to_mem_ecc_a[(72*data_slice_a)-9 -: 64] = {dina_i[(64*data_slice_a)-1],~dina_i[(64*data_slice_a)-2] ,dina_i[(64*data_slice_a)-3 -: 31],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 -: 30]}; + din_to_mem_ecc_a[(72*data_slice_a)-1 -: 8] = fn_ecc_enc_dec(1'b1, dina_i[(64*data_slice_a)-1 -: 64], 8'h00); + end + end + else if(injectsbiterra_sim) begin + for (integer data_slice_a=1; data_slice_a <= WRITE_DATA_WIDTH_A/64; data_slice_a=data_slice_a+1) begin + din_to_mem_ecc_a[(72*data_slice_a)-9 -: 64] = {dina_i[(64*data_slice_a)-1 -:33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 -: 30]}; + din_to_mem_ecc_a[(72*data_slice_a)-1 -: 8] = fn_ecc_enc_dec(1'b1, dina_i[(64*data_slice_a)-1 -: 64], 8'h00); + end + end + else begin + for (integer data_slice_a=1; data_slice_a <= WRITE_DATA_WIDTH_A/64; data_slice_a=data_slice_a+1) begin + din_to_mem_ecc_a[(72*data_slice_a)-9 -: 64] = dina_i[(64*data_slice_a)-1 -: 64]; + din_to_mem_ecc_a[(72*data_slice_a)-1 -: 8] = fn_ecc_enc_dec(1'b1, dina_i[(64*data_slice_a)-1 -: 64], 8'h00); + end + end + doutb_int <= din_to_mem_ecc_a; + end + else begin + if(addrb_aslp_sim < P_MAX_DEPTH_DATA) + doutb_int <= mem_ecc[addrb_i]; + else + doutb_int <= 'bX; + end + end + else begin + if(addrb_aslp_sim < P_MAX_DEPTH_DATA) + doutb_int <= mem_ecc[addrb_i]; + else + doutb_int <= 'bX; + end + assign gen_rd_b.doutb_reg = doutb_int; + end + end : data_out_proc_b + end : data_enc_only + + if (`MEM_PORTA_READ && (`MEM_PRIM_ULTRA || `MEM_PRIM_AUTO)) begin : data_out_proc_a + // Here the write mode can be Write First, Read First or No Change for + // SPRAM, and for TDP it is always No Change + if (`MEM_PORTA_RF) begin : rf_prta + always @(posedge clka) begin + if (rsta && READ_LATENCY_A == 1) + deassign gen_rd_a.douta_reg; + else if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1))) begin + if(addra_aslp_sim < P_MAX_DEPTH_DATA) + douta_int <= mem_ecc[addra_i]; + else + douta_int <= 'bX; + assign gen_rd_a.douta_reg = douta_int; + end + end + end : rf_prta + if (`MEM_PORTA_NC) begin : nc_prta + always @(posedge clka) begin + if (rsta && READ_LATENCY_A == 1) + deassign gen_rd_a.douta_reg; + else if(ena_i & ~(|wea_i) && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1))) begin + if(addra_aslp_sim < P_MAX_DEPTH_DATA) + douta_int <= mem_ecc[addra_i]; + else + douta_int <= 'bX; + assign gen_rd_a.douta_reg = douta_int; + end + end + end : nc_prta + if (`MEM_PORTA_WF) begin : wf_prta + for (genvar data_slice_a=1; data_slice_a <= WRITE_DATA_WIDTH_A/64; data_slice_a=data_slice_a+1) begin : ecc_data_calc_a + always @(*) begin : ecc_enc_only_data_wr + if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1)) && addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(|wea_i) begin + if(injectdbiterra_sim) + din_to_mem_ecc_a[(72*data_slice_a)-9 : (72*data_slice_a)-72] = {dina_i[(64*data_slice_a)-1],~dina_i[(64*data_slice_a)-2] ,dina_i[(64*data_slice_a)-3 : (64*data_slice_a)-33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 : (data_slice_a-1)*64]}; + else if(injectsbiterra_sim) + din_to_mem_ecc_a[(72*data_slice_a)-9 : (72*data_slice_a)-72] = {dina_i[(64*data_slice_a)-1 : (64*data_slice_a)-33],~dina_i[(64*data_slice_a)-34],dina_i[(64*data_slice_a)-35 : (data_slice_a-1)*64]}; + else + din_to_mem_ecc_a[(72*data_slice_a)-9 : (72*data_slice_a)-72] = dina_i[(64*data_slice_a)-1 : (data_slice_a-1)*64]; + din_to_mem_ecc_a[(72*data_slice_a)-1 : (72*data_slice_a)-8] = fn_ecc_enc_dec(1'b1, dina_i[(64*data_slice_a)-1 : (data_slice_a-1)*64], 8'h00); + end + end + end : ecc_enc_only_data_wr + end : ecc_data_calc_a + always @(posedge clka) begin + if (rsta && READ_LATENCY_A == 1) + deassign gen_rd_a.douta_reg; + else if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1))) begin + if (addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(|wea_i) + douta_int <= din_to_mem_ecc_a; + else + douta_int <= mem_ecc[addra_i]; + end + else begin + douta_int <= 'bX; + end + assign gen_rd_a.douta_reg = douta_int; + end + end + end : wf_prta + end : data_out_proc_a + end : en_enc_only + + // ------------------------------------------------------------------------------------------------------------------- + /**ECC Behavioral Modeling when Decoder only is enabled + This module need not perform the parity calculation as the parity needs to be supplied by the user + But, this needs to check the parity correctness and assert the error + status bits. (sbiterr and dbiterr status signals) + This module needs to model the Error Injection + **/ + // ------------------------------------------------------------------------------------------------------------------- + + if ((ECC_MODE == 3 && !(`NO_MEMORY_INIT)) || ECC_MODE == 2) begin : en_dec_only + // memory declaration (aspect ratio is not supported when ECC Enabled) + reg [0:0] sbiterra_status [0:P_MAX_DEPTH_DATA-1]; + reg [0:0] dbiterra_status [0:P_MAX_DEPTH_DATA-1]; + reg [7:0] synda_i [(WRITE_DATA_WIDTH_A/72)-1:0]; + reg [7:0] synda_calc [(WRITE_DATA_WIDTH_A/72)-1:0]; + reg [(WRITE_DATA_WIDTH_A/72)-1:0] sbita_calc; + reg [(WRITE_DATA_WIDTH_A/72)-1:0] dbita_calc; + reg [WRITE_DATA_WIDTH_A-1 : 0] douta_frm_mem_ecc = 'b0; + reg [READ_DATA_WIDTH_A-1 : 0] douta_frm_mem_ecc_out = 'b0; // always to be in multiples of 64, data to be forced on to dout + + reg [0:0] sbiterrb_status [0:P_MAX_DEPTH_DATA-1]; + reg [0:0] dbiterrb_status [0:P_MAX_DEPTH_DATA-1]; + reg [7:0] syndb_i [(WRITE_DATA_WIDTH_A/72)-1:0]; + reg [7:0] syndb_calc [(WRITE_DATA_WIDTH_A/72)-1:0]; + reg [(WRITE_DATA_WIDTH_A/72)-1:0] sbitb_calc; + reg [(WRITE_DATA_WIDTH_A/72)-1:0] dbitb_calc; + reg [WRITE_DATA_WIDTH_A-1 : 0] doutb_frm_mem_ecc = 'b0; + reg [READ_DATA_WIDTH_B-1 : 0] doutb_frm_mem_ecc_out = 'b0; // always to be in multiples of 64, data to be forced on to dout + + initial begin + sbiterra_int <= 1'b0; + dbiterra_int <= 1'b0; + sbiterrb_int <= 1'b0; + dbiterrb_int <= 1'b0; + end + + // Data is expected to be in the multiples of 72-bits + // Data - parity calculation can be continuously calculated + // and compare it with what user supplied + + // The Implementation involves in 3 steps : + // 1. Memory Array in this case needs to be created with the width being + // multiple of 72 bits + // 2. write the data to the memory + // 3. Always Read the data from memory based on the address, and separate + // data and parity bits + // 4. calculate the parity bits on the data + // 5. compare the user supplied parity bits with calculated syndrome bits + + // Data to be written to the memory array, no error injection in decode only mode + if(ECC_MODE == 2) begin :data_dec_only + always @(posedge clka) begin : ecc_dec_only_data_wr + if(ena_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1)) && addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if(`MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP) begin + if (!(enb_i && |web_i && addrb_i == addra_i)) begin + if(|wea_i) + mem_ecc[addra_i] <= dina_i; + end + end + else begin + if(|wea_i) + mem_ecc[addra_i] <= dina_i; + end + end + end : ecc_dec_only_data_wr + if (`MEM_PORTB_WRITE && (`MEM_PRIM_ULTRA || `MEM_PRIM_AUTO)) begin : data_in_proc_b + always @(posedge gen_wr_b.clkb_int) begin + if(enb_i && (~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1)) && addrb_aslp_sim < P_MAX_DEPTH_DATA) begin + if(|web_i) + mem_ecc[addrb_i] <= dinb_i; + end + end + end : data_in_proc_b + end : data_dec_only + + if (`MEM_PORTB_READ) begin : data_out_proc_b + for (genvar dat_par_slice_b=1; dat_par_slice_b <= WRITE_DATA_WIDTH_A/72; dat_par_slice_b = dat_par_slice_b+1) begin : ecc_par_calc_b + always @(*) begin + if (enb_i & ~|web_i) begin + if(`MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP) begin + if (ena_i) begin + if(|wea_i && (addra_i == addrb_i)) + doutb_frm_mem_ecc = dina_i; + else + doutb_frm_mem_ecc = mem_ecc[addrb_i]; + end + else + doutb_frm_mem_ecc = mem_ecc[addrb_i]; + end + else + doutb_frm_mem_ecc = mem_ecc[addrb_i]; + syndb_i[dat_par_slice_b-1] = fn_ecc_enc_dec(1'b0, doutb_frm_mem_ecc[(72*dat_par_slice_b)-9 : (72*dat_par_slice_b)-72], doutb_frm_mem_ecc[(72*dat_par_slice_b)-1 : (72*dat_par_slice_b)-8]); + syndb_calc[dat_par_slice_b-1] = syndb_i[dat_par_slice_b-1] ^ doutb_frm_mem_ecc[(72*dat_par_slice_b)-1 : (72*dat_par_slice_b)-8]; + sbitb_calc[dat_par_slice_b-1] = |syndb_calc[dat_par_slice_b-1] && syndb_calc[dat_par_slice_b-1][7]; + dbitb_calc[dat_par_slice_b-1] = |syndb_calc[dat_par_slice_b-1] && ~syndb_calc[dat_par_slice_b-1][7]; + if(sbitb_calc[dat_par_slice_b-1] && ~dbitb_calc[dat_par_slice_b-1]) + doutb_frm_mem_ecc_out[(64*dat_par_slice_b)-1 : (64*dat_par_slice_b)-64] = fn_correct_bit(syndb_calc[dat_par_slice_b-1], doutb_frm_mem_ecc[(72*dat_par_slice_b)-9 : (72*dat_par_slice_b)-72],doutb_frm_mem_ecc[(72*dat_par_slice_b)-1 : (72*dat_par_slice_b)-8]); + else + doutb_frm_mem_ecc_out[(64*dat_par_slice_b)-1 : (64*dat_par_slice_b)-64] = doutb_frm_mem_ecc[(72*dat_par_slice_b)-9 : (72*dat_par_slice_b)-72]; + end + end + end : ecc_par_calc_b + + always @(posedge gen_rd_b.clkb_int) begin: data_gen_proc + if (sleep_int_a == 1'b1 || sleep_int_b == 1'b1) begin + if(enb_i & ~(|web_i)) begin + sbiterrb_int <= 1'bX; + dbiterrb_int <= 1'bX; + end + end + else if (rstb && READ_LATENCY_B == 1) begin + assign gen_rd_b.doutb_reg = gen_rd_b.rstb_val; + sbiterrb_int <= 0; + dbiterrb_int <= 0; + end + else if(enb_i & ~(|web_i)) begin + if (addrb_aslp_sim >= P_MAX_DEPTH_DATA) begin + doutb_int <= 'bX; + sbiterrb_int <= 1'bX; + dbiterrb_int <= 1'bX; + end + else begin + doutb_int <= doutb_frm_mem_ecc_out; + sbiterrb_int <= |sbitb_calc; + dbiterrb_int <= |dbitb_calc; + end + assign gen_rd_b.doutb_reg = doutb_int; + end + assign gen_rd_b.pipeline_ecc_status.sbiterrb_in_pipe = sbiterrb_int; + assign gen_rd_b.pipeline_ecc_status.dbiterrb_in_pipe = dbiterrb_int; + end : data_gen_proc + end : data_out_proc_b + + if (`MEM_PORTA_READ && (`MEM_PRIM_ULTRA || `MEM_PRIM_AUTO)) begin : data_out_proc_a + for (genvar dat_par_slice_a=1; dat_par_slice_a <= WRITE_DATA_WIDTH_A/72; dat_par_slice_a = dat_par_slice_a+1) begin : ecc_par_calc_a + always @(*) begin + if (addra_aslp_sim < P_MAX_DEPTH_DATA) begin + if (ena_i) begin + if(`MEM_PORTA_WF) begin + if(|wea_i) + douta_frm_mem_ecc = dina_i; + else + douta_frm_mem_ecc = mem_ecc[addra_i]; + end + else begin + douta_frm_mem_ecc = mem_ecc[addra_i]; + end + synda_i[dat_par_slice_a-1] = fn_ecc_enc_dec(1'b0, douta_frm_mem_ecc[(72*dat_par_slice_a)-9 : (72*dat_par_slice_a)-72], douta_frm_mem_ecc[(72*dat_par_slice_a)-1 : (72*dat_par_slice_a)-8]); + synda_calc[dat_par_slice_a-1] = synda_i[dat_par_slice_a-1] ^ douta_frm_mem_ecc[(72*dat_par_slice_a)-1 : (72*dat_par_slice_a)-8]; + sbita_calc[dat_par_slice_a-1] = |synda_calc[dat_par_slice_a-1] && synda_calc[dat_par_slice_a-1][7]; + dbita_calc[dat_par_slice_a-1] = |synda_calc[dat_par_slice_a-1] && ~synda_calc[dat_par_slice_a-1][7]; + if(sbita_calc[dat_par_slice_a-1] && ~dbita_calc[dat_par_slice_a-1]) + douta_frm_mem_ecc_out[(64*dat_par_slice_a)-1 : (64*dat_par_slice_a)-64] = fn_correct_bit(synda_calc[dat_par_slice_a-1], douta_frm_mem_ecc[(72*dat_par_slice_a)-9 : (72*dat_par_slice_a)-72],douta_frm_mem_ecc[(72*dat_par_slice_a)-1 : (72*dat_par_slice_a)-8]); + else + douta_frm_mem_ecc_out[(64*dat_par_slice_a)-1 : (64*dat_par_slice_a)-64] = douta_frm_mem_ecc[(72*dat_par_slice_a)-9 : (72*dat_par_slice_a)-72]; + end + end + else begin + douta_frm_mem_ecc_out = 'bX; + sbita_calc = 'bX; + dbita_calc = 'bX; + end + end + end : ecc_par_calc_a + + if (`MEM_PORTA_RF || `MEM_PORTA_WF) begin : rf_prta + always @(posedge clka) begin: data_gen_proc + if (sleep_int_a == 1'b1 || sleep_int_b == 1'b1) begin + if (ena_i) begin + sbiterra_int <= 1'bX; + dbiterra_int <= 1'bX; + end + end + else if (rsta && READ_LATENCY_A == 1) begin + assign gen_rd_a.douta_reg = gen_rd_a.rsta_val; + sbiterra_int <= 0; + dbiterra_int <= 0; + end + else if(ena_i) begin + if (addra_aslp_sim >= P_MAX_DEPTH_DATA) begin + douta_int <= 'bX; + sbiterra_int <= 1'bX; + dbiterra_int <= 1'bX; + end + else begin + douta_int <= douta_frm_mem_ecc_out; + sbiterra_int <= |sbita_calc; + dbiterra_int <= |dbita_calc; + end + assign gen_rd_a.douta_reg = douta_int; + end + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.sbiterra_in_pipe = sbiterra_int; + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.dbiterra_in_pipe = dbiterra_int; + end : data_gen_proc + end : rf_prta + + if (`MEM_PORTA_NC) begin : nc_prta + always @(posedge clka) begin: data_gen_proc + if (sleep_int_a == 1'b1 || sleep_int_b == 1'b1) begin + if(ena_i & ~(|wea_i)) begin + sbiterra_int <= 1'bX; + dbiterra_int <= 1'bX; + end + end + else if (rsta && READ_LATENCY_A == 1) begin + assign gen_rd_a.douta_reg = gen_rd_a.rsta_val; + sbiterra_int <= 0; + dbiterra_int <= 0; + end + else if(ena_i & ~(|wea_i)) begin + if (addra_aslp_sim >= P_MAX_DEPTH_DATA) begin + douta_int <= 'bX; + sbiterra_int <= 1'bX; + dbiterra_int <= 1'bX; + end + else begin + douta_int <= douta_frm_mem_ecc_out; + sbiterra_int <= |sbita_calc; + dbiterra_int <= |dbita_calc; + end + assign gen_rd_a.douta_reg = douta_int; + end + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.sbiterra_in_pipe = sbiterra_int; + assign gen_rd_a.pipeline_ecc_status.status_out_proc_a.dbiterra_in_pipe = dbiterra_int; + end : data_gen_proc + end : nc_prta + end : data_out_proc_a + end : en_dec_only + end : ecc_behav_logic + + // ------------------------------------------------------------------------------------------------------------------- + // Asymmetry with Byte Write Enable Across Ports Implementation + // ------------------------------------------------------------------------------------------------------------------- + + if (`DISABLE_SYNTH_TEMPL) begin : gen_beh_model_bbox + `ifndef OBSOLETE + `ifndef DISABLE_XPM_ASSERTIONS + initial begin + if(SIM_ASSERT_CHK == 1) begin : chk_vld_asym_bwe_only_configs + /* + Check for the following conditions, + 1. Byte writes enabled on both ports with Byte size being 8,9 + 2. Byte writes are enabled on only one port and the other being word wide read + */ + if(`MEM_PORTA_WRITE && `MEM_PORTA_WR_BYTE && `MEM_TYPE_RAM_SDP) begin + $info("XPM_MEMORY_ASSYM_BWE-1: Configuration selected is having Byte writes on Port-A, and the Read side is word-wide Read (Memory type is set to SDP)"); + end + + if(`MEM_PORTA_WRITE && `MEM_PORTA_WR_BYTE && `MEM_TYPE_RAM_TDP) begin + $info("XPM_MEMORY_ASSYM_BWE-2: Configuration selected is having Byte writes on Port-A, and the Read side is word-wide Read (Memory type is set to TDP)"); + end + + if(`MEM_PORTA_WR_BYTE && `MEM_PORTB_WR_BYTE && BYTE_WRITE_WIDTH_A == 8 && `MEM_TYPE_RAM_TDP) begin + $info("XPM_MEMORY_ASSYM_BWE-3: Configuration selected is having Byte writes on Port-A and Port-B (Memory type is set to TDP, and byte size is 8)"); + end + + if(`MEM_PORTA_WR_BYTE && !`MEM_PORTB_WR_BYTE && `MEM_TYPE_RAM_TDP) begin + $info("XPM_MEMORY_ASSYM_BWE-4: Configuration selected is having Byte writes on Port-A and the Read side is word-wide Read on Port-B (Memory type is set to TDP)"); + end + + if(!`MEM_PORTA_WR_BYTE && `MEM_PORTB_WR_BYTE && `MEM_TYPE_RAM_TDP) begin + $info("XPM_MEMORY_ASSYM_BWE-5: Configuration selected is having Byte writes on Port-B and the Read side is word-wide Read on Port-A (Memory type is set to TDP)"); + end + + if(`MEM_PORTA_WR_BYTE && `MEM_PORTB_WR_BYTE && BYTE_WRITE_WIDTH_A == 9 && `MEM_TYPE_RAM_TDP) begin + $info("XPM_MEMORY_ASSYM_BWE-6: Configuration selected is having Byte writes (byte width is 9) on Port-A and Port-B (Memory type is set to TDP)"); + end + end : chk_vld_asym_bwe_only_configs + end + `endif + `endif + + localparam READ_DATA_WIDTH_A_ECC_ASYM = `NO_ECC ? READ_DATA_WIDTH_A : P_MIN_WIDTH_DATA_ECC; + localparam READ_DATA_WIDTH_B_ECC_ASYM = `NO_ECC ? READ_DATA_WIDTH_B : P_MIN_WIDTH_DATA_ECC; + localparam logic [READ_DATA_WIDTH_A_ECC_ASYM-1:0] rsta_val_asym = `ASYNC_RESET_A ? {READ_DATA_WIDTH_A_ECC_ASYM{1'b0}} : rst_val_conv_a(READ_RESET_VALUE_A); + localparam logic [READ_DATA_WIDTH_B_ECC_ASYM-1:0] rstb_val_asym = `ASYNC_RESET_B ? {READ_DATA_WIDTH_B_ECC_ASYM{1'b0}} : rst_val_conv_b(READ_RESET_VALUE_B); + + if(`MEM_PORTA_WRITE) begin : gen_wr_a_asymbwe + if(`MEM_PORTA_WR_BYTE) begin : gen_wr_bwe + if(`MEM_PORTA_WR_NARROW) begin : gen_byte_narrow + reg [P_MIN_WIDTH_DATA_ECC-1:0] i_tmp_dat_storage_a = 0; + reg [READ_DATA_WIDTH_A-1:0] o_tmp_dat_storage_a = rsta_val_asym; + if(`MEM_PORTA_READ && `MEM_PORTA_WF) begin : port_a_write_read + always @(posedge clka) begin : wr_dat + if(ena_i & ~(sleep_int_a == 1'b1 || sleep_int_b == 1'b1)) begin + if(|wea_i) begin + i_tmp_dat_storage_a = mem[addra_i]; + for(integer byte_cnt=1; byte_cnt<=P_NUM_COLS_WRITE_A; byte_cnt=byte_cnt+1) begin + if(wea_i[byte_cnt-1]) begin + i_tmp_dat_storage_a[(byte_cnt*BYTE_WRITE_WIDTH_A)-1 -: BYTE_WRITE_WIDTH_A] = dina_i[(byte_cnt*BYTE_WRITE_WIDTH_A)-1 -: BYTE_WRITE_WIDTH_A]; + end + end + mem[addra_i] <= i_tmp_dat_storage_a; + end + end + end : wr_dat + if(READ_LATENCY_A == 1) begin : gen_narrow_wf_rd_reg + if(`ASYNC_RESET_A) begin + always @(posedge rsta or posedge clka) begin : wr_dat_rd + if(rsta) + o_tmp_dat_storage_a <= rsta_val_asym; + else begin + for (integer col=0; col= AUTO_SLEEP_TIME) + ena_activity_cnt <= ena_activity_cnt; + else + ena_activity_cnt <= ena_activity_cnt + 1'b1; + end + else + ena_activity_cnt <= 'b0; + end + // Enable pipe line Delay Enable by Auto Sleep Number of times + reg ena_aslp_pipe [AUTO_SLEEP_TIME-1:0]; + // Initialize the ena pipeline + initial begin + integer aslp_initstage_a; + for (aslp_initstage_a=0; aslp_initstage_a < AUTO_SLEEP_TIME; aslp_initstage_a=aslp_initstage_a+1) begin : for_en_pipe_init + ena_aslp_pipe[aslp_initstage_a] = 1'b0; + end : for_en_pipe_init + end + + // This code may needs to be mode up + always @(posedge clka) + begin + ena_aslp_pipe[0] <= ena; + end + for (genvar aslp_stage=1; aslp_stage < AUTO_SLEEP_TIME; aslp_stage = aslp_stage+1) begin : gen_aslp_inp_pipe + always @(posedge clka) begin + ena_aslp_pipe[aslp_stage] <= ena_aslp_pipe[aslp_stage-1]; + end + end : gen_aslp_inp_pipe + + + always @(posedge clka) begin + if(ena_aslp_pipe[AUTO_SLEEP_TIME-2]) + aslp_mode_active_a = 1'b0; + else begin + if(ena_aslp_pipe[AUTO_SLEEP_TIME-1] == 1'b0 && ena_activity_cnt >= AUTO_SLEEP_TIME) + aslp_mode_active_a <= 1'b1; + end + end + // Place Memory to Auto sleep only when there is no activity on both ports + assign aslp_mode_active = aslp_mode_active_a & aslp_mode_active_b; + + // Assign delayed enable to "en_i" for the memory write to happen + always @(posedge clka) begin + force ena_i = ena_aslp_pipe[AUTO_SLEEP_TIME-1]; + end + if (READ_LATENCY_A == 1) begin : aslp_en_a + if(`ASYNC_RESET_A) begin : async_aslp_en_a + always @(posedge rsta or posedge clka) begin + if(rsta) begin + force douta = gen_rd_a.rsta_val; + end + else begin + if(aslp_mode_active) begin + force douta = 'bX; + end + else begin + if(`MEM_PORTA_NC) begin + if(ena_i & ~(|wea_i)) begin + release douta; + end + end + else begin + if(ena_i) begin + release douta; + end + end + end + end + end + end : async_aslp_en_a + else begin : sync_aslp_en_a + always @(posedge clka) begin + if(rsta) begin + force douta = gen_rd_a.rsta_val; + end + else begin + if(aslp_mode_active) begin + force douta = 'bX; + end + else begin + if(`MEM_PORTA_NC) begin + if(ena_i & ~(|wea_i)) begin + release douta; + end + end + else begin + if(ena_i) begin + release douta; + end + end + end + end + end + end : sync_aslp_en_a + always @(posedge clka) begin + if(rsta) begin + force sbiterra = 1'b0; + force dbiterra = 1'b0; + end + else begin + if(aslp_mode_active) begin + force sbiterra = 'bX; + force dbiterra = 'bX; + end + else begin + if(`MEM_PORTA_NC) begin + if(ena_i & ~(|wea_i)) begin + release sbiterra; + release dbiterra; + end + end + else begin + if(ena_i) begin + release sbiterra; + release dbiterra; + end + end + end + end + end + end : aslp_en_a + if(`MEM_PORTB_READ) begin : gen_aslp_b_rd + reg enb_aslp_pipe [AUTO_SLEEP_TIME-1:0]; + // Initialize the enb pipelines + initial begin + integer aslp_initstage_b; + for (aslp_initstage_b=0; aslp_initstage_b= AUTO_SLEEP_TIME) + enb_activity_cnt <= enb_activity_cnt; + else + enb_activity_cnt <= enb_activity_cnt + 1'b1; + end + else + enb_activity_cnt <= 'b0; + end + + always @(posedge gen_auto_slp_dly_b.clkb_int) begin + if(enb_aslp_pipe[AUTO_SLEEP_TIME-2]) + aslp_mode_active_b = 1'b0; + else begin + if(enb_aslp_pipe[AUTO_SLEEP_TIME-1] == 1'b0 && enb_activity_cnt >= AUTO_SLEEP_TIME) + aslp_mode_active_b <= 1'b1; + end + end + // Delay the Enable, this code may needs to be mode up + always @(posedge gen_auto_slp_dly_b.clkb_int) + begin + enb_aslp_pipe[0] <= enb; + end + for (genvar aslp_stage=1; aslp_stage < AUTO_SLEEP_TIME; aslp_stage = aslp_stage+1) begin : gen_aslp_inp_pipe + always @(posedge gen_auto_slp_dly_b.clkb_int) begin + enb_aslp_pipe[aslp_stage] <= enb_aslp_pipe[aslp_stage-1]; + end + end : gen_aslp_inp_pipe + // Assign delayed enable to "en_i" for the memory write to happen + always @(posedge gen_auto_slp_dly_b.clkb_int) begin + force enb_i = enb_aslp_pipe[AUTO_SLEEP_TIME-1]; + end + if (READ_LATENCY_B == 1) begin : aslp_en_b + //always @(posedge gen_auto_slp_dly_b.clkb_int) begin + if(`ASYNC_RESET_B) begin : async_aslp_en_b + always @(posedge rstb or posedge clka) begin // sampling on clka to make to sure that both ports drive-x at the same time + if(rstb) begin + force doutb = gen_rd_b.rstb_val; + end + else begin + if(aslp_mode_active) begin + force doutb = 'bX; + end + else begin + if(`MEM_PORTB_NC) begin + if(enb_i & ~(|web_i)) begin + release doutb; + end + end + else begin + if(enb_i) begin + release doutb; + end + end + end + end + end + end : async_aslp_en_b + else begin : sync_aslp_en_b + always @(posedge clka) begin // sampling on clka to make to sure that both ports drive-x at the same time + if(rstb) begin + force doutb = gen_rd_b.rstb_val; + end + else begin + if(aslp_mode_active) begin + force doutb = 'bX; + end + else begin + if(`MEM_PORTB_NC) begin + if(enb_i & ~(|web_i)) begin + release doutb; + end + end + else begin + if(enb_i) begin + release doutb; + end + end + end + end + end + end : sync_aslp_en_b + always @(posedge clka) begin // sampling on clka to make to sure that both ports drive-x at the same time + if(rstb) begin + force sbiterrb = 1'b0; + force dbiterrb = 1'b0; + end + else begin + if(aslp_mode_active) begin + force sbiterrb = 'bX; + force dbiterrb = 'bX; + end + else begin + if(`MEM_PORTB_NC) begin + if(enb_i & ~(|web_i)) begin + release sbiterrb; + release dbiterrb; + end + end + else begin + if(enb_i) begin + release sbiterrb; + release dbiterrb; + end + end + end + end + end + end : aslp_en_b + end : gen_aslp_b_rd + + `ifndef OBSOLETE + `ifndef DISABLE_XPM_ASSERTIONS + + wire clkb_int; + if (`COMMON_CLOCK) begin + assign clkb_int = clka; + end + else if (`INDEPENDENT_CLOCKS) begin + assign clkb_int = clkb; + end + wire [P_WIDTH_ADDR_WRITE_A-1:0] effctv_addra_aslp = addra; + wire [P_WIDTH_ADDR_WRITE_B-1:0] effctv_addrb_aslp = addrb; + if (`REPORT_MESSAGES && `MEM_PORTA_WRITE) begin : illegal_wr_ena_aslp + assert property (@(posedge clka) + !(ena && |wea && (addra > effctv_addra_aslp) )) + else + $warning("XPM_MEMORY_OUT_OF_RANGE_WRITE_ACCESS : Write Operation on Port-A to an out-of-range address at time %0t; Actual Address --> %0h , effective address is %0h.There is a chance that data at the effective address location may get written in the synthesis netlist, and there by the simulation mismatch can occur between behavioral model and netlist simulations", $time,addra,effctv_addra_aslp); + end : illegal_wr_ena_aslp + + if (`REPORT_MESSAGES && `MEM_PORTB_WRITE) begin : illegal_wr_enb_aslp + assert property (@(posedge clkb_int) + !(enb && |web && (addrb > effctv_addrb_aslp) )) + else + $warning("XPM_MEMORY_OUT_OF_RANGE_WRITE_ACCESS : Write Operation on Port-B to an out-of-range address at time %0t; Actual Address --> %0h , effective address is %0h.There is a chance that data at the effective address location may get written in the synthesis netlist, and there by the simulation mismatch can occur between behavioral model and netlist simulations", $time,addrb,effctv_addrb_aslp); + end : illegal_wr_enb_aslp + + if (`REPORT_MESSAGES && `MEM_PORTA_WRITE && `MEM_PORTA_NC) begin : unsupported_wr_ena + assert property (@(posedge clka) + !(aslp_mode_active && ena && |wea)) + else + $warning("XPM_MEMORY_WR_IN_ASLP_NC : Write Operation on Port-A at time %0t when in Auto Sleep mode and the write mode is set to No_Change, at address : addra(%h);behavioral and netlist simulation may not match for the data output corresponding to this write operation.", $time,addra); + end : unsupported_wr_ena + + if (`REPORT_MESSAGES && `MEM_PORTB_WRITE && `MEM_PORTB_NC) begin : unsupported_wr_enb + assert property (@(posedge clkb_int) + !(aslp_mode_active && enb && |web)) + else + $warning("XPM_MEMORY_WR_IN_ASLP_NC : Write Operation on Port-B at time %0t when in Auto Sleep mode and the write mode is set to No_Change, at address : addrb(%h); behavioral and netlist simulation may not match for the data output corresponding to this write operation.", $time,addrb); + end : unsupported_wr_enb + + if(SIM_ASSERT_CHK == 1) begin : chk_vld_aslp_configs + if(`MEM_AUTO_SLP_EN && `MEM_PRIM_ULTRA) begin : assrt_chks_aslp + assert property (@(posedge clka) + !(ena_activity_cnt >= AUTO_SLEEP_TIME)) + $info("XPM_MEMORY_ASLP_EN: ena is active, and the memory cannot enter Auto Sleep Mode"); + else + $info("XPM_MEMORY_ASLP_EN: ena in-active (%t) for more than AUTO_SLEEP_TIME", $time); + + if(`MEM_PORTB_READ || `MEM_PORTB_WRITE) begin : assrt_chks_aslp_b + assert property (@(posedge clkb) + !(enb_activity_cnt >= AUTO_SLEEP_TIME)) + $info("XPM_MEMORY_ASLP_EN: enb is active, and the memory cannot enter Auto Sleep Mode"); + else + $info("XPM_MEMORY_ASLP_EN: enb in-active (%t) for more than AUTO_SLEEP_TIME", $time); + assert property (@(posedge clka) + !(aslp_mode_active & (ena & ~enb))) + else + $info("XPM_MEMORY_ASLP_EN: Memory is in AUTO_SLEEP, and Port-A enable (ena) alone is asserted at time (%t) to bring the memory to active mode.", $time); + + assert property (@(posedge clkb) + !(aslp_mode_active & (~ena & enb))) + else + $info("XPM_MEMORY_ASLP_EN: Memory is in AUTO_SLEEP, and Port-B enable (enb) alone is asserted at time (%t) to bring the memory to active mode.", $time); + end : assrt_chks_aslp_b + end : assrt_chks_aslp + end : chk_vld_aslp_configs + `endif + `endif + end : gen_alsp_model + + // UltraRAM TDP mode Modeling + // below conditions to be taken care. + /** If both ports are executing read and write for the same address, : + //If port A is writing, port B is reading, then port B reads new data. + //If port A is reading, port B is writing, then port A reads the old data. + //If port A and B are writing, then port B write overwrites the port A write. At the end of the clock cycle, the memory stores port B write data. + **/ + // When the address does not overlap - then do we need to model any behavior? + + if (`MEM_PRIM_ULTRA && `MEM_TYPE_RAM_TDP && `NO_ECC) begin : uram_tdp_model + + reg [P_MIN_WIDTH_DATA-1:0] mem_col [0:P_MAX_DEPTH_DATA-1]; + reg [READ_DATA_WIDTH_A-1 : 0] douta_col = 0; + reg [READ_DATA_WIDTH_B-1 : 0] doutb_col = 0; + wire [P_WIDTH_ADDR_WRITE_A-1:0] addra_int = addra_i; + wire [P_WIDTH_ADDR_WRITE_B-1:0] addrb_int ; + wire rstb_int; + wire enb_int; + wire [(WRITE_DATA_WIDTH_B/BYTE_WRITE_WIDTH_B)-1:0] web_int ; + wire [READ_DATA_WIDTH_B-1 : 0] dinb_int; + wire #1 clkb_int_i = gen_rd_b.clkb_int; + + assign #2 addrb_int = addrb_i; + assign #2 rstb_int = rstb; + assign #2 enb_int = enb_i; + assign #2 web_int = web_i; + assign #2 dinb_int = dinb_i; + + integer row; + reg [P_WIDTH_ADDR_LSB_WRITE_A-1:0] addralsb; + reg [P_WIDTH_ADDR_LSB_READ_A-1:0] addralsb_rd; + reg [P_WIDTH_ADDR_LSB_WRITE_B-1:0] addrblsb; + reg [P_WIDTH_ADDR_LSB_READ_B-1:0] addrblsb_rd; + // Memory Array Initialization + //initial begin + // integer col_initword; + // for (col_initword=0; col_initword