// ---------------------------------------------------------------------
//
//                   (C) COPYRIGHT 2005-2011 SYNOPSYS INC.
//                             ALL RIGHTS RESERVED
//
//  This software and the associated documentation are confidential and
//  proprietary to Synopsys Inc.  Your use or disclosure of this software
//  is subject to the terms and conditions of a written license agreement
//  between you or your company, and Synopsys, Inc.
//
//  The entire notice above must be reproduced on all authorized copies.
//
// -------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Filename    : DW_axi_x2h_resp_buffer
// 
// Created     : Tues Dec 21 20:00:00 GMT 2004
// Description : Connects to the DWbb fifo control and the registers
//               Allows for a single or two clocks, selects fifo based on 
//               clocking
//               The AXI side pushes with the response
//   
//-----------------------------------------------------------------------------

module i_axi_x2h_DW_axi_x2h_resp_buffer(/*AUTOARG*/
  // Outputs
  hresp_rdy_int_n, aresp_rdy_int_n, awstatus_int, awid_int, 
  // Inputs
  clk_axi, clk_ahb, hwstatus_int, hwid_int, push_resp_int_n, 
  pop_resp_int_n, push_rst_n, pop_rst_n
                              );
  
     // requires the following to be defined
//  X2H_AXI_DATA_WIDTH      width of the read data word;
//  X2H_AXI_ID_WIDTH        width of the read id
//  X2H_WRITE_RESP_BUFFER_DEPTH   depth of the FIFO
   
//  X2H_CLK_MODE           0 = Async Clocks implies FIFO with 2 or 3 push and pop sync 
//                         1 = Sync Clocks  imnplies FIFO with 1 push and pop sync
//                         2 = single clock implies a single clock fifo
    // if X2H_CLK_MODE=0 the following will be used
//  X2H_SYNC_MODE          number of clocks used in both the push and pop sections when asynchronous clocking   
  input                   clk_axi;
  input                   clk_ahb; 
  input [1:0] hwstatus_int;
  input [`X2H_AXI_ID_WIDTH-1:0] hwid_int;
  input       push_resp_int_n;
  output      hresp_rdy_int_n;
  output      aresp_rdy_int_n;
  output [1:0] awstatus_int;
  output [`X2H_AXI_ID_WIDTH-1:0] awid_int;
  input        pop_resp_int_n;
  input        push_rst_n;
  input        pop_rst_n;  
  
`define fifo_width `X2H_AXI_ID_WIDTH+2                // fixed for ID plus status
`define depth `X2H_WRITE_RESP_BUFFER_DEPTH
// push and pop syncs for dual clock systems.
// if the clock are sync use 1 reg between domains
// if async use the constraint
`define push_sync ((`X2H_CLK_MODE==0) ? `X2H_SYNC_MODE : 1)
`define pop_sync  ((`X2H_CLK_MODE==0) ? `X2H_SYNC_MODE : 1)
// set up all the widths and depths assume here that the depth cannot exceed 256
`define count_width ((`depth <= 2) ? 2 :(`depth <= 4) ? 3 :(`depth <= 8) ? 4 :(`depth <= 16) ? 5:(`depth <= 32) ? 6:(`depth <= 64) ? 7:(`depth <= 128) ? 8:9)
`define DW_addr_width  (`count_width-1)
   // adjusting the RAM depth for odd and non-power of 2 compatibility with the control
   // if FIFO is  dual-clocked adjusting the RAM depth for odd and non-power of 2 compatibility with the control
`define DW_effective_depth_s1 `depth 
`define DW_effective_depth_s2 ((`depth == (1 << `DW_addr_width))? `depth : `depth + ((`depth & 1) ? 1: 2))
`define DW_effective_depth ((`X2H_CLK_MODE==2) ? `DW_effective_depth_s1 : `DW_effective_depth_s2)

  reg  [`DW_addr_width-1:0] wr_addr,rd_addr;
  wire [`DW_addr_width-1:0] s1_wr_addr,s1_rd_addr,s2_wr_addr,s2_rd_addr;
  wire                      tie_low,tie_hi,mem_rst_n;
  reg                       aresp_rdy_int_n,hresp_rdy_int_n;
  reg                       s1_rst_n,s2_push_rst_n,s2_pop_rst_n;
  reg                       we_n;
  
  assign                    mem_rst_n = push_rst_n;
  assign                    tie_low = 1'b0;
  assign                    tie_hi  = 1'b1;
 `define push_ae_lvl 2
 `define push_af_lvl 2
 `define pop_ae_lvl 2
 `define pop_af_lvl 2
 `define err_mode 0  
 `define tst_mode 0      // scan test input not connected

  reg clk_push;
  reg clk_pop;
  wire [`DW_addr_width-1:0]  af_thresh,ae_level;
  wire                       s1_hresp_rdy_int_n, s1_aresp_rdy_int_n, s1_we_n;
  wire                       s2_hresp_rdy_int_n, s2_aresp_rdy_int_n, s2_we_n;
  
  assign                     af_thresh = `DW_effective_depth-1;
  //leda clean up
  //The following assignment has the potential to lose the msb due to truncation.
  //however, we don't use the almost_empty fifo output so remove this assignment
  //and drive ae_level to 0.
  //assign                     ae_level = `push_ae_lvl;
    assign                     ae_level = 0;

  //leda W287 off
  //turn off checks for unconnected ports
// call fifo Controller
  i_axi_x2h_DW_axi_x2h_bcm06
   #(`depth,`tst_mode, `DW_addr_width)
      U_RESP_FIFO_CONTROL_S1(
                .clk(clk_axi),
                .rst_n(s1_rst_n),
                .init_n(tie_hi),
                .full(s1_hresp_rdy_int_n),
                .empty(s1_aresp_rdy_int_n),                        
                .af_thresh(af_thresh),                        
                .diag_n(tie_hi),
                .ae_level(ae_level),
                .push_req_n(push_resp_int_n),
                .pop_req_n(pop_resp_int_n),
                .we_n(s1_we_n),
                .wr_addr(s1_wr_addr),
                .rd_addr(s1_rd_addr),
                .almost_empty(),
                .half_full(),
                .almost_full(),
                .error(),
                .wrd_count(),
                .nxt_empty_n(),
                .nxt_full(),
                .nxt_error()          
                 );

  i_axi_x2h_DW_axi_x2h_bcm07
   #(`depth,`DW_addr_width,`count_width,
                       `push_ae_lvl,
                       `push_af_lvl,
                       `pop_ae_lvl,
                       `pop_af_lvl,
                       `err_mode,
                       `push_sync,
                       `pop_sync,
                       `tst_mode
                       )
    U_RESP_FIFO_CONTROL_S2(
                .clk_push(clk_push),
                .clk_pop(clk_pop),
                .test(tie_low),                          
                .rst_push_n(s2_push_rst_n),
                .init_push_n(tie_hi ),           
                .rst_pop_n(s2_pop_rst_n),
                .init_pop_n(tie_hi ),            
                .push_full(s2_hresp_rdy_int_n),
                .pop_empty(s2_aresp_rdy_int_n),                                
                .push_req_n(push_resp_int_n),
                .pop_req_n(pop_resp_int_n),
                .we_n(s2_we_n),
                .wr_addr(s2_wr_addr),
                .rd_addr(s2_rd_addr),
                .push_empty(),
                .push_ae(),
                .push_hf(),
                .push_af(),
                .push_error(),
                .push_word_count(),
                .pop_ae(),
 	        .pop_hf(),
	        .pop_af(),
	        .pop_full(),
	        .pop_error(),
                .pop_word_count()                          
                 );
//leda W287 on
  
  // feeding the outputs from the appropriate control
  always @(/*AS*/clk_ahb or clk_axi or pop_rst_n
           or push_rst_n or s1_aresp_rdy_int_n or s1_hresp_rdy_int_n
           or s1_rd_addr or s1_we_n or s1_wr_addr
           or s2_aresp_rdy_int_n or s2_hresp_rdy_int_n or s2_rd_addr
           or s2_we_n or s2_wr_addr)
    begin
      if (`X2H_CLK_MODE==2)  // use the single clock
        begin
          s2_push_rst_n = 1'b0;  // hold the unusd control
          s2_pop_rst_n = 1'b0;  // hold the unusd control
          s1_rst_n = push_rst_n; 
         // the RAM
          we_n = s1_we_n;
          rd_addr = s1_rd_addr;
          wr_addr = s1_wr_addr;          
          // going out
          aresp_rdy_int_n = s1_aresp_rdy_int_n;
          hresp_rdy_int_n = s1_hresp_rdy_int_n;
           // clocking single clock use the axi
          clk_push = clk_axi;
          clk_pop = clk_axi;          
       end
      else
        begin
          s1_rst_n = 1'b0;  // hold the unusd control in reset
          s2_push_rst_n = push_rst_n;
          s2_pop_rst_n = pop_rst_n;
          we_n = s2_we_n;
          rd_addr = s2_rd_addr;
          wr_addr = s2_wr_addr;        
          aresp_rdy_int_n = s2_aresp_rdy_int_n;
          hresp_rdy_int_n = s2_hresp_rdy_int_n;        
          // clocking ahb does the pushing
          clk_push = clk_ahb;
          clk_pop = clk_axi;          
       end // else: !if(`X2H_CLK_MODE==2)
    end // always @ (... 

  // The RAM
  i_axi_x2h_DW_axi_x2h_bcm57
   #(`fifo_width,`DW_effective_depth,0,`DW_addr_width)
     U_RESP_FIFO_RAM(.init_n(tie_hi),                   
                      .clk(clk_push),
                      .rst_n(mem_rst_n),
                      .wr_n(we_n),
                      .rd_addr(rd_addr),
                      .wr_addr(wr_addr),
                      .data_in({hwstatus_int,hwid_int}),
                      .data_out({awstatus_int,awid_int})
                      );

// uesd in all the fifos for undefine defines
 `undef depth
 `undef DW_effective_depth_s1                         
 `undef DW_effective_depth_s2                         
 `undef DW_effective_depth                         
 `undef DW_addr_width
 `undef push_ae_lvl
 `undef push_af_lvl
 `undef pop_ae_lvl
 `undef pop_af_lvl
 `undef err_mode
 `undef push_sync
 `undef pop_sync
 `undef tst_mode 
 `undef count_width
 `undef fifo_width                       

    endmodule // AXI_RESP_BUFFER


