// =============================================================================
// Generated by efx_ipmgr
// Version: 2023.1.150
// IP Version: 5.0
// =============================================================================

////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2023 Efinix Inc. All rights reserved.              
//
// This   document  contains  proprietary information  which   is        
// protected by  copyright. All rights  are reserved.  This notice       
// refers to original work by Efinix, Inc. which may be derivitive       
// of other work distributed under license of the authors.  In the       
// case of derivative work, nothing in this notice overrides the         
// original author's license agreement.  Where applicable, the           
// original license agreement is included in it's original               
// unmodified form immediately below this header.                        
//                                                                       
// WARRANTY DISCLAIMER.                                                  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND        
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH               
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES,  
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF          
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR    
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED       
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.           
//                                                                       
// LIMITATION OF LIABILITY.                                              
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY       
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT    
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY   
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT,      
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY    
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF      
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR   
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN    
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER    
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR            
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT   
//     APPLY TO LICENSEE.                                                
//
////////////////////////////////////////////////////////////////////////////////

`define IP_UUID _8fa1502251ff4c338cc5b2fd6c7f050a
`define IP_NAME_CONCAT(a,b) a``b
`define IP_MODULE_NAME(name) `IP_NAME_CONCAT(name,`IP_UUID)
module sdram_controller (
input i_we,
input i_sysclk,
input i_arst,
input i_sdrclk,
input i_tACclk,
input i_pll_locked,
input i_re,
input i_last,
output o_dbg_tRTW_done,
output o_dbg_ref_req,
output o_dbg_wr_ack,
output o_dbg_rd_ack,
output [1:0] o_dbg_n_CS,
output [1:0] o_dbg_n_RAS,
output [1:0] o_dbg_n_CAS,
output [1:0] o_dbg_n_WE,
output [3:0] o_dbg_BA,
output [25:0] o_dbg_ADDR,
output [31:0] o_dbg_DATA_out,
output [31:0] o_dbg_DATA_in,
input [23:0] i_addr,
input [31:0] i_din,
input [3:0] i_dm,
output [31:0] o_dout,
output [3:0] o_sdr_state,
output o_sdr_init_done,
output o_wr_ack,
output o_rd_ack,
output o_ref_req,
output o_rd_valid,
output [1:0] o_sdr_CKE,
output [1:0] o_sdr_n_CS,
output [1:0] o_sdr_n_RAS,
output [1:0] o_sdr_n_CAS,
output [1:0] o_sdr_n_WE,
output [3:0] o_sdr_BA,
output [25:0] o_sdr_ADDR,
output [31:0] o_sdr_DATA,
output [31:0] o_sdr_DATA_oe,
input [31:0] i_sdr_DATA,
output [3:0] o_sdr_DQM,
output [5:0] o_dbg_dly_cnt_b,
output o_dbg_tRCD_done
);
`IP_MODULE_NAME(efx_sdram_controller) #(
.fSYS_MHz (100),
.fCK_MHz (200),
.tIORT_u (2),
.CL (3),
.BL (1),
.DDIO_TYPE ("SOFT"),
.DQ_WIDTH (8),
.DQ_GROUP (2),
.BA_WIDTH (2),
.ROW_WIDTH (13),
.COL_WIDTH (9),
.tPWRUP (200000),
.tRAS (44),
.tRAS_MAX (120000),
.tRC (66),
.tRCD (20),
.tREF (64000000),
.tRFC (66),
.tRP (20),
.tWR (2),
.tMRD (2),
.SDRAM_MODE ("Native"),
.DATA_RATE (2),
.AXI_AWADDR_WIDTH (24),
.AXI_WDATA_WIDTH (32),
.AXI_ARADDR_WIDTH (24),
.AXI_RDATA_WIDTH (32),
.AXI_AWID_WIDTH (4),
.AXI_AWUSER_WIDTH (2),
.AXI_WUSER_WIDTH (2),
.AXI_BID_WIDTH (4),
.AXI_BUSER_WIDTH (2),
.AXI_ARID_WIDTH (4),
.AXI_ARUSER_WIDTH (3),
.AXI_RUSER_WIDTH (3)
) u_efx_sdram_controller(
.i_we ( i_we ),
.i_sysclk ( i_sysclk ),
.i_arst ( i_arst ),
.i_sdrclk ( i_sdrclk ),
.i_tACclk ( i_tACclk ),
.i_pll_locked ( i_pll_locked ),
.i_re ( i_re ),
.i_last ( i_last ),
.o_dbg_tRTW_done ( o_dbg_tRTW_done ),
.o_dbg_ref_req ( o_dbg_ref_req ),
.o_dbg_wr_ack ( o_dbg_wr_ack ),
.o_dbg_rd_ack ( o_dbg_rd_ack ),
.o_dbg_n_CS ( o_dbg_n_CS ),
.o_dbg_n_RAS ( o_dbg_n_RAS ),
.o_dbg_n_CAS ( o_dbg_n_CAS ),
.o_dbg_n_WE ( o_dbg_n_WE ),
.o_dbg_BA ( o_dbg_BA ),
.o_dbg_ADDR ( o_dbg_ADDR ),
.o_dbg_DATA_out ( o_dbg_DATA_out ),
.o_dbg_DATA_in ( o_dbg_DATA_in ),
.i_addr ( i_addr ),
.i_din ( i_din ),
.i_dm ( i_dm ),
.o_dout ( o_dout ),
.o_sdr_state ( o_sdr_state ),
.o_sdr_init_done ( o_sdr_init_done ),
.o_wr_ack ( o_wr_ack ),
.o_rd_ack ( o_rd_ack ),
.o_ref_req ( o_ref_req ),
.o_rd_valid ( o_rd_valid ),
.o_sdr_CKE ( o_sdr_CKE ),
.o_sdr_n_CS ( o_sdr_n_CS ),
.o_sdr_n_RAS ( o_sdr_n_RAS ),
.o_sdr_n_CAS ( o_sdr_n_CAS ),
.o_sdr_n_WE ( o_sdr_n_WE ),
.o_sdr_BA ( o_sdr_BA ),
.o_sdr_ADDR ( o_sdr_ADDR ),
.o_sdr_DATA ( o_sdr_DATA ),
.o_sdr_DATA_oe ( o_sdr_DATA_oe ),
.i_sdr_DATA ( i_sdr_DATA ),
.o_sdr_DQM ( o_sdr_DQM ),
.o_dbg_dly_cnt_b ( o_dbg_dly_cnt_b ),
.o_dbg_tRCD_done ( o_dbg_tRCD_done )
);

endmodule

/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(axi4_sdram_controller).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      sdram contronller top with AXI4 interface
//  /_/ /\ \_____/ /     
// ____/  \_______/     
//
// *******************************
// Revisions:
// 1.0 Initial rev
//  Support ONLY AXI 32-bit data to SDRAM total DQ x16 half rate
//
// *******************************
/////////////////////////////////////////////////////////////////////////////
// AxSIZE
`define	BYTES_TX_1		3'b000
`define	BYTES_TX_2		3'b001
`define	BYTES_TX_4		3'b010
`define	BYTES_TX_8		3'b011
`define	BYTES_TX_16		3'b100
`define	BYTES_TX_32		3'b101
`define	BYTES_TX_64		3'b110
`define	BYTES_TX_128	3'b111
`define	OKAY	2'b00

module `IP_MODULE_NAME(axi4_sdram_controller)
#(
	parameter	AXI_AWADDR_WIDTH	= 32,
	parameter	AXI_WDATA_WIDTH		= 32,
	parameter	AXI_ARADDR_WIDTH	= 32,
	parameter	AXI_RDATA_WIDTH		= 32,
                                    
	parameter	fSYS_MHz		= 100,
	parameter	fCK_MHz			= 100,
	parameter	DDIO_TYPE		= "SOFT",
	parameter	tPWRUP			= 100,			// 100 us
	parameter	tRAS			= 44,			// 44 ns
	parameter	tRAS_MAX		= 120,		// 120 us
	parameter	tRC			    = 66,			// 66 ns
	parameter	tRCD			= 20,			// 20 ns
	parameter	tREF			= 64,			// 64 ms
	parameter	tRFC			= 66,			// 66 ns
	parameter	tRP			    = 20,			// 20 ns
	parameter	tWR			    = 2,			// 1 CK+7.5 ns
	parameter	tMRD			= 2,			// 2 CK
	parameter	CL			    = 3,			// 3 CK
	parameter	BL			    = 1,
    parameter   DATA_RATE       = 1,
    parameter   tIORT_u		    = 2,
	parameter	BA_WIDTH		= 2,
	parameter	ROW_WIDTH		= 10,
	parameter	COL_WIDTH		= 10,
	parameter	DQ_WIDTH		= 8,	// x4, x8
	parameter	DQ_GROUP		= 8,
	//			x4	x8	x16	x32
	// DQ_WIDTH	4	8	8	8
	// DQ_GROUP	1	1	2	4
	// AXI not support DQ_WIDTH = 4 DQ_GROUP = 1
	
	//----- parameter not configurable by user----
	parameter	AXI_AWID_WIDTH		= 4,
	parameter	AXI_AWUSER_WIDTH	= 2,
	parameter	AXI_WUSER_WIDTH		= 2,
	parameter	AXI_BID_WIDTH		= 4,
	parameter	AXI_BUSER_WIDTH		= 2,
	parameter	AXI_ARID_WIDTH		= 4,
	parameter	AXI_ARUSER_WIDTH	= 2,
	parameter	AXI_RUSER_WIDTH		= 2
)
(
	input	i_aresetn,
	input	i_sysclk,
	input	i_sdrclk,
	input	i_tACclk,
	input	i_pll_locked,
	output	o_pll_reset,
	
	// Compulsory
	output	o_AXI4_AWREADY,
	input	[AXI_AWADDR_WIDTH-1:0]i_AXI4_AWADDR,
	input	[2:0]i_AXI4_AWPROT,	// Dummy
	input	i_AXI4_AWVALID,
	
	output	o_AXI4_WREADY,
	input	[AXI_WDATA_WIDTH/8-1:0]i_AXI4_WSTRB,
	input	[AXI_WDATA_WIDTH-1:0]i_AXI4_WDATA,
	input	i_AXI4_WLAST,
	input	i_AXI4_WVALID,
	
	output	o_AXI4_BVALID,
	input	i_AXI4_BREADY,
	
	output	o_AXI4_ARREADY,
	input	[AXI_ARADDR_WIDTH-1:0]i_AXI4_ARADDR,
	input	[2:0]i_AXI4_ARPROT,		// Dummy
	input	i_AXI4_ARVALID,
	
	input	i_AXI4_RREADY,
	output	[AXI_RDATA_WIDTH-1:0]o_AXI4_RDATA,
	output	o_AXI4_RLAST,
	output	o_AXI4_RVALID,
	
	// Optional
	input	[AXI_AWID_WIDTH-1:0]i_AXI4_AWID,
	input	[3:0]i_AXI4_AWREGION,					// Dummy
	input	[7:0]i_AXI4_AWLEN,						// Dummy
	input	[2:0]i_AXI4_AWSIZE,
	input	[1:0]i_AXI4_AWBURST,					// Dummy
	input	i_AXI4_AWLOCK,							// Dummy
	input	[3:0]i_AXI4_AWCACHE,					// Dummy
	input	[3:0]i_AXI4_AWQOS,						// Dummy
	input	[AXI_AWUSER_WIDTH-1:0]i_AXI4_AWUSER,	// Dummy
	
	input	[AXI_WUSER_WIDTH-1:0]i_AXI4_WUSER,		// Dummy
	
	output	[AXI_BID_WIDTH-1:0]o_AXI4_BID,
	output	[1:0]o_AXI4_BRESP,						// Dummy
	output	[AXI_BUSER_WIDTH-1:0]o_AXI4_BUSER,		// Dummy
	
	input	[AXI_ARID_WIDTH-1:0]i_AXI4_ARID,
	input	[3:0]i_AXI4_ARREGION,					// Dummy
	input	[7:0]i_AXI4_ARLEN,
	input	[2:0]i_AXI4_ARSIZE,
	input	[1:0]i_AXI4_ARBURST,					// Dummy
	input	i_AXI4_ARLOCK,							// Dummy
	input	[3:0]i_AXI4_ARCACHE,					// Dummy
	input	[3:0]i_AXI4_ARQOS,						// Dummy
	input	[AXI_ARUSER_WIDTH-1:0]i_AXI4_ARUSER,	// Dummy
	
	output	[AXI_ARID_WIDTH-1:0]o_AXI4_RID,
	output	[1:0]o_AXI4_RRESP,						// Dummy
	output	[AXI_RUSER_WIDTH-1:0]o_AXI4_RUSER,		// Dummy
	
	output	[DATA_RATE							-1:0]	o_sdr_CKE,
	output	[DATA_RATE							-1:0]	o_sdr_n_CS,
	output	[DATA_RATE							-1:0]	o_sdr_n_RAS,
	output	[DATA_RATE							-1:0]	o_sdr_n_CAS,
	output	[DATA_RATE							-1:0]	o_sdr_n_WE,
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_sdr_BA,
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_sdr_ADDR,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA_oe,
	input	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	i_sdr_DATA,
	output	[DATA_RATE	*DQ_GROUP				-1:0]	o_sdr_DQM,
	
	// Debug port
	output	[3:0]o_sdr_state,
	output	o_dbg_we,
	output	o_dbg_re,
	output	o_dbg_last,
	output	[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:0]o_dbg_addr,
	output	[AXI_WDATA_WIDTH-1:0]o_dbg_din,
	output	o_dbg_wr_ack,
	output	o_dbg_rd_ack,
	output	o_sdr_rd_valid,
	output	o_dbg_ref_req,
	output	[DATA_RATE*DQ_GROUP*DQ_WIDTH+AXI_ARID_WIDTH:0]o_sdr_dout,
	output	[1:0]o_axi4_wrstate,
	output	o_dbg_axi4_wlast,
	output	[1:0]o_axi4_rastate,
	output	[1:0]o_axi4_rdstate,
	output	o_axi4_nwr,
	output	o_re_lock,
	output	[6:0]o_shift_cnt,
	output	[7:0]o_axi4_arlen,
	output	o_fifo_wr,
	output	o_fifo_full,
	output	o_fifo_empty,
	output	o_dbg_fifo_we,
	output	[7:0]o_dbg_fifo_waddr,
	output	o_dbg_fifo_re,
	output	[7:0]o_dbg_fifo_raddr,
	
	output	[DATA_RATE							-1:0]	o_dbg_n_CS,
	output	[DATA_RATE							-1:0]	o_dbg_n_RAS,
	output	[DATA_RATE							-1:0]	o_dbg_n_CAS,
	output	[DATA_RATE							-1:0]	o_dbg_n_WE,
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_dbg_BA,
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_dbg_ADDR,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_dbg_DATA_out,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_dbg_DATA_in
);

function integer log2;
	input	integer	val;
	integer	i;
	begin
		log2 = 0;
		for (i=0; 2**i<val; i=i+1)
			log2 = i+1;
	end
endfunction

initial
begin
	$display("DQ_GROUP: %d\n", DQ_GROUP);
	$display("DQ_WIDTH: %d\n", DQ_WIDTH);
end

`ifdef RTL_SIM
        localparam   tIORT		    = 1; //(DATA_RATE == 2 && CL == 2) ? 1 : 0;
`else
        localparam   tIORT		    = tIORT_u;
`endif

localparam	s_INIT		= 2'b00;
localparam	s_IDLE		= 2'b01;
localparam	s_WR_SHIFT	= 2'b10;
localparam	s_WR_RESP	= 2'b11;
localparam	s_RD_ADDR	= 2'b10;
localparam	s_RD_INIT	= 2'b10;
localparam	s_RD_SHIFT	= 2'b11;
localparam	SDR_DWIDTH	= DQ_GROUP*DQ_WIDTH;
localparam	SDR_BWIDTH	= DATA_RATE*SDR_DWIDTH;
localparam	DIN_WIDTH	= AXI_WDATA_WIDTH;
localparam	DOUT_WIDTH	= AXI_RDATA_WIDTH;

wire    r_AXI4_WREADY_c;

reg		[1:0]r_axi4_wrstate_1P;
reg		[1:0]r_axi4_rastate_1P;
reg		[1:0]r_axi4_rdstate_1P;
reg		r_axi4_nwr_1P;
reg		r_AXI4_AWREADY_1P;
reg		r_AXI4_AWLEN_1P;
//reg		r_AXI4_WREADY_c;
reg		r_AXI4_WLAST_1P;
reg		r_AXI4_BVALID_1P;
reg		r_AXI4_ARREADY_1P;
reg		[7:0]r_AXI4_ARLEN_1P;
reg		r_AXI4_RVALID_1P;
reg		[AXI_BID_WIDTH-1:0]r_AXI4_BID_1P;
reg		[AXI_ARID_WIDTH-1:0]r_AXI4_RID_1P;

reg		r_we_1P;
reg		r_re_1P;
reg		r_last_1P;
reg		[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:0]r_addr_1P;
reg		[DIN_WIDTH-1:0]r_din_1P;
reg     [DIN_WIDTH/8-1:0]r_dm_1P;
reg		[6:0]r_size_1P;
reg		[6:0]r_shift_cnt_1P;
reg		[6:0]r_addr_cnt_1P;
reg		[7:0]r_arlen_cnt_1P;
reg		[8:0]arlen_cnt;

reg		r_wr_ack_1P;
reg		r_AXI4_WREADY_2P;
reg		r_re_lock_1P;

reg		[AXI_ARID_WIDTH-1:0]r_AXI4_RID[0:CL+tIORT+1];
reg		[DOUT_WIDTH+AXI_ARID_WIDTH:0]r_dout_1P;
reg		r_fifo_wr_1P;
reg		r_fifo_rd_1P;

wire	[SDR_BWIDTH-1:0]w_dout;
wire	w_sdr_init_done;
wire	w_wr_ack;
wire	w_rd_ack;
wire	w_ref_req;
wire	w_rd_valid;

wire	[AXI_RDATA_WIDTH+AXI_ARID_WIDTH:0]w_fifo_dout;
wire    rd_last;
wire	w_afull;
wire	w_empty;

wire	[1:0]c_addr_increment;
assign	c_addr_increment	= DATA_RATE;
assign	o_pll_reset			= i_aresetn;

`IP_MODULE_NAME(sdram_controller)
#(
	.fSYS_MHz			(fSYS_MHz),
	.fCK_MHz			(fCK_MHz),
	.REF_LATENCY		(4),
	.tIORT_u		    (tIORT_u),
	.DDIO_TYPE			(DDIO_TYPE),
	.tPWRUP				(tPWRUP),	// 100 us
	.tRAS				(tRAS),		// 44 ns
	.tRAS_MAX			(tRAS_MAX),	// 120 us
	.tRC				(tRC),		// 66 ns
	.tRCD				(tRCD),		// 20 ns
	.tREF				(tREF),		// 64 ms
	.tRFC				(tRFC),		// 66 ns
	.tRP				(tRP),		// 20 ns
	.tWR				(tWR),		// 1 CK+7.5 ns
	.tMRD				(tMRD),		// 2 CK
	.CL					(CL),		// 3 CK
	.BL					(BL),
	.BA_WIDTH			(BA_WIDTH),
	.ROW_WIDTH			(ROW_WIDTH),
	.COL_WIDTH			(COL_WIDTH),
    .DATA_RATE          (DATA_RATE),
	.DQ_WIDTH			(DQ_WIDTH),	// x4, x8
	.DQ_GROUP			(DQ_GROUP)
	//			x4	x8	x16	x32
	// DQ_WIDTH	4	8	8	8
	// DQ_GROUP	1	1	2	4
)
inst_sdram_controller
(
	.i_arst			(~i_aresetn),
	.i_sysclk		(i_sysclk),
	.i_sdrclk		(i_sdrclk),
	.i_tACclk		(i_tACclk),
	.i_pll_locked	(i_pll_locked),
	
	.i_we			(r_we_1P),
	.i_re			(r_re_1P),
	.i_last			(r_last_1P),
	.i_addr			(r_addr_1P),
	.i_din			(r_din_1P[SDR_BWIDTH-1:0]),
    .i_dm           (r_dm_1P[(SDR_BWIDTH/8)-1:0]),
	.o_dout			(w_dout),
	.o_sdr_state	(o_sdr_state),	// debug use
	.o_sdr_init_done(w_sdr_init_done),
	.o_wr_ack		(w_wr_ack),
	.o_rd_ack		(w_rd_ack),
	.o_ref_req		(w_ref_req),
	.o_rd_valid		(w_rd_valid),
	
	.o_sdr_CKE		(o_sdr_CKE),
	.o_sdr_n_CS		(o_sdr_n_CS),
	.o_sdr_n_RAS	(o_sdr_n_RAS),
	.o_sdr_n_CAS	(o_sdr_n_CAS),
	.o_sdr_n_WE		(o_sdr_n_WE),
	.o_sdr_BA		(o_sdr_BA),
	.o_sdr_ADDR		(o_sdr_ADDR),
	.o_sdr_DATA		(o_sdr_DATA),
	.o_sdr_DATA_oe	(o_sdr_DATA_oe),
	.i_sdr_DATA		(i_sdr_DATA),
	.o_sdr_DQM		(o_sdr_DQM),
	
	.o_dbg_ref_req	(o_dbg_ref_req),
	.o_dbg_n_CS		(o_dbg_n_CS),
	.o_dbg_n_RAS	(o_dbg_n_RAS),
	.o_dbg_n_CAS	(o_dbg_n_CAS),
	.o_dbg_n_WE		(o_dbg_n_WE),
	.o_dbg_BA		(o_dbg_BA),
	.o_dbg_ADDR		(o_dbg_ADDR),
	.o_dbg_DATA_out	(o_dbg_DATA_out),
	.o_dbg_DATA_in	(o_dbg_DATA_in),
	.o_dbg_wr_ack	(o_dbg_wr_ack),
	.o_dbg_rd_ack	(o_dbg_rd_ack)
);

`IP_MODULE_NAME(dual_clock_fifo_wrapper)
#(
	.DATA_WIDTH(AXI_RDATA_WIDTH+AXI_ARID_WIDTH+1),
	.ADDR_WIDTH(8),
	.LATENCY(2),
	.FIFO_MODE("STD_FIFO"),
	.RAM_INIT_FILE(""),
	.COMPATIBILITY("E"),
	.OUTPUT_REG("FALSE"),
	.CHECK_FULL("TRUE"),
	.CHECK_EMPTY("TRUE"),
	.AFULL_THRESHOLD(2**8-1),
	.AEMPTY_THRESHOLD(1)
)
inst_dual_clock_fifo_wrapper
(
	.i_arst(~i_aresetn),
	
	.i_wclk(i_sysclk),
	.i_we(r_fifo_wr_1P),
	.i_wdata(r_dout_1P),
	
	.i_rclk(i_sysclk),
	.i_re(r_fifo_rd_1P || (r_AXI4_RVALID_1P && i_AXI4_RREADY)),
	
	.o_full(w_afull),
	.o_empty(w_empty),
	.o_rdata(w_fifo_dout),

	.o_afull(),
	.o_wcnt(),
	.o_aempty(),
	.o_rcnt(),
	
	.o_dbg_we(o_dbg_fifo_we),
	.o_dbg_waddr(o_dbg_fifo_waddr),
	.o_dbg_re(o_dbg_fifo_re),
	.o_dbg_raddr(o_dbg_fifo_raddr)
);

always@(negedge i_aresetn or posedge i_sysclk)
begin
	if (~i_aresetn)
	begin
		r_axi4_wrstate_1P	<= s_INIT;
		r_axi4_rastate_1P	<= s_INIT;
		r_axi4_rdstate_1P	<= s_INIT;
		r_axi4_nwr_1P		<= 1'b0;
		
		r_AXI4_AWREADY_1P	<= 1'b0;
		r_AXI4_AWLEN_1P		<= 1'b0;
		//r_AXI4_WREADY_c	<= 1'b0;
		r_AXI4_WLAST_1P		<= 1'b0;
		r_AXI4_BVALID_1P	<= 1'b0;
		r_AXI4_ARREADY_1P	<= 1'b0;
		r_AXI4_ARLEN_1P		<= {8{1'b0}};
		r_AXI4_RVALID_1P	<= 1'b0;
		r_AXI4_BID_1P		<= {AXI_BID_WIDTH{1'b0}};
		r_AXI4_RID_1P		<= {AXI_ARID_WIDTH{1'b0}};
		
		r_we_1P				<= 1'b0;
		r_re_1P				<= 1'b0;
		r_last_1P			<= 1'b0;
		r_addr_1P			<= {BA_WIDTH+ROW_WIDTH+COL_WIDTH{1'b0}};
		r_din_1P			<= {DIN_WIDTH{1'b0}};
		r_dm_1P             <= {DIN_WIDTH/8{1'b0}};
		r_size_1P			<= {7{1'b0}};
		r_shift_cnt_1P		<= {7{1'b0}};
		arlen_cnt           <= {9{1'b0}};
		r_addr_cnt_1P		<= {7{1'b0}};
		r_arlen_cnt_1P		<= {8{1'b0}};
		
		r_wr_ack_1P			<= 1'b0;
		r_AXI4_WREADY_2P	<= 1'b0;
		r_re_lock_1P		<= 1'b0;
		
		r_AXI4_RID[0]		<= {AXI_ARID_WIDTH{1'b0}};
		r_dout_1P			<= {DOUT_WIDTH+AXI_ARID_WIDTH+1{1'b0}};
		r_fifo_wr_1P		<= 1'b0;
		r_fifo_rd_1P		<= 1'b0;
	end
	else if (i_pll_locked)
	begin
		r_axi4_nwr_1P		<= ~r_axi4_nwr_1P;
		r_AXI4_AWREADY_1P	<= 1'b0;
		//r_AXI4_WREADY_c	<= 1'b0;
		r_AXI4_ARREADY_1P	<= 1'b0;
		
		r_wr_ack_1P			<= w_wr_ack;
		r_AXI4_WREADY_2P	<= r_AXI4_WREADY_c;
		
		r_AXI4_RID[0]		<= r_AXI4_RID_1P;
		r_fifo_wr_1P		<= 1'b0;
		r_fifo_rd_1P		<= 1'b0;
		
		case (r_axi4_wrstate_1P)
			s_INIT:
			begin
				if (w_sdr_init_done)
					r_axi4_wrstate_1P	<= s_IDLE;
			end
			
			s_IDLE:
			begin
				if (i_AXI4_AWVALID && i_AXI4_WVALID &&
					~r_axi4_nwr_1P && ~r_re_lock_1P)
				begin
					r_axi4_wrstate_1P	<= s_WR_SHIFT;
					r_AXI4_AWREADY_1P	<= 1'b1;
					if (i_AXI4_AWLEN != {8{1'b0}})
						r_AXI4_AWLEN_1P	<= 1'b1;
					else
						r_AXI4_AWLEN_1P	<= 1'b0;
					r_AXI4_WLAST_1P		<= i_AXI4_WLAST;
					if (AXI_AWID_WIDTH >= AXI_BID_WIDTH)
						r_AXI4_BID_1P	<= i_AXI4_AWID[AXI_BID_WIDTH-1:0];
					else
						r_AXI4_BID_1P	<= {{AXI_BID_WIDTH-AXI_AWID_WIDTH{1'b0}}, i_AXI4_AWID};
					
					r_we_1P			<= 1'b1;
					// TODO AXI different width support
					if (SDR_BWIDTH > AXI_WDATA_WIDTH)
					begin
						r_addr_1P[0+:BA_WIDTH+ROW_WIDTH+COL_WIDTH-(0-SDR_BWIDTH/AXI_WDATA_WIDTH+1)]	<= i_AXI4_AWADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:0-SDR_BWIDTH/AXI_WDATA_WIDTH+1];
						$display("foo_gt\n");
					end
					else if (SDR_BWIDTH == AXI_WDATA_WIDTH)
					begin
						r_addr_1P	<= {i_AXI4_AWADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:COL_WIDTH], {(DATA_RATE-1){1'b0}}, i_AXI4_AWADDR[COL_WIDTH-1:DATA_RATE-1]};
						//r_addr_1P	<= {{(DATA_RATE-1){1'b0}},i_AXI4_AWADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:DATA_RATE-1]};
						$display("foo_eq\n");
					end
					
					if (SDR_BWIDTH > AXI_WDATA_WIDTH)
					begin
						//r_AXI4_WREADY_c				<= 1'b1;
						r_size_1P						<= SDR_BWIDTH/AXI_WDATA_WIDTH-1'b1;
						r_shift_cnt_1P					<= SDR_BWIDTH/AXI_WDATA_WIDTH-1'b1;
						$display("SDR_BWIDTH %d > AXI_WDATA_WIDTH %d\n", SDR_BWIDTH, AXI_WDATA_WIDTH);
					end
					else if (SDR_BWIDTH == AXI_WDATA_WIDTH)
					begin
						if (i_AXI4_WLAST)
						begin
							r_din_1P			<= i_AXI4_WDATA;
							r_dm_1P             <= i_AXI4_WSTRB ^ {(AXI_WDATA_WIDTH/8){1'b1}}; //bitwise XOR to inver the bit
							r_last_1P			<= 1'b1;
						end
						r_size_1P			<= SDR_BWIDTH/AXI_WDATA_WIDTH-1'b1;
						r_shift_cnt_1P		<= {7{1'b0}};
						$display("SDR_BWIDTH %d = AXI_WDATA_WIDTH %d\n", SDR_BWIDTH, AXI_WDATA_WIDTH);
					end
					else
					begin
						//r_AXI4_WREADY_c	<= 1'b1;
						r_size_1P			<= AXI_WDATA_WIDTH/SDR_BWIDTH-1'b1;
						r_shift_cnt_1P		<= AXI_WDATA_WIDTH/SDR_BWIDTH-1'b1;
						$display("SDR_BWIDTH %d < AXI_WDATA_WIDTH %d\n", SDR_BWIDTH, AXI_WDATA_WIDTH);
					end
				end
			end
			
			s_WR_SHIFT:
			begin
				if (SDR_BWIDTH > AXI_WDATA_WIDTH)
				begin
					if (r_shift_cnt_1P != 7'd0)
					begin
						if (r_AXI4_WREADY_c)
							r_shift_cnt_1P		<= r_shift_cnt_1P-1'b1;
					end
					else
					begin
						r_shift_cnt_1P		<= r_size_1P;
					end
				end		
				else if (SDR_BWIDTH == AXI_WDATA_WIDTH)
				begin
					if (r_AXI4_WREADY_2P)
						r_addr_1P	<= r_addr_1P+c_addr_increment;
					
					if (r_AXI4_WREADY_c) 
				    begin
						r_din_1P	<= i_AXI4_WDATA;
					    r_dm_1P     <= i_AXI4_WSTRB ^ {(AXI_WDATA_WIDTH/8){1'b1}}; //bitwise XOR to inver the bit;
					end
					
					if (~r_AXI4_WREADY_c & r_AXI4_WREADY_2P & i_AXI4_WLAST)
					begin
						r_din_1P	<= i_AXI4_WDATA;
						r_dm_1P     <= i_AXI4_WSTRB ^ {(AXI_WDATA_WIDTH/8){1'b1}}; //bitwise XOR to inver the bit;
					end
				end
				
				if (w_wr_ack)
				begin
					/*if (SDR_BWIDTH < AXI_WDATA_WIDTH)
					begin
						if (r_size_1P != `BYTES_TX_1)
							r_addr_1P	<= r_addr_1P+c_addr_increment;
						else if (~r_wr_ack_1P)
							r_addr_1P	<= r_addr_1P+c_addr_increment;
						else if (r_AXI4_WREADY_2P)
							r_addr_1P	<= r_addr_1P+c_addr_increment;
						
						r_shift_cnt_1P	<= r_shift_cnt_1P-1'b1;
						if (r_AXI4_WLAST_1P && r_shift_cnt_1P == 7'd1)
							r_last_1P	<= 1'b1;
					end
					else if (SDR_BWIDTH == AXI_WDATA_WIDTH)
					begin
						r_AXI4_WREADY_c	<= 1'b1;
					end
					else
					begin
						r_AXI4_WREADY_c	<= 1'b1;
						
						if (r_AXI4_WREADY_c)
							r_addr_1P	<= r_addr_1P+1'b1;
						
						if (r_shift_cnt_1P == 7'd1)
						begin
							if (i_AXI4_WLAST || r_AXI4_WLAST_1P)
							begin
								r_axi4_wrstate_1P	<= s_WR_RESP;
								r_AXI4_WREADY_c	<= 1'b0;
								r_AXI4_WLAST_1P		<= 1'b0;
								r_AXI4_BVALID_1P	<= 1'b1;
								
								r_last_1P			<= 1'b1;
							end
						end
					end*/
					
					if (r_shift_cnt_1P == 7'd0)
					begin	
						//r_AXI4_WREADY_c	<= 1'b1;
						
						r_AXI4_WLAST_1P	<= i_AXI4_WLAST;
						r_shift_cnt_1P	<= r_size_1P;
						
						if (i_AXI4_WLAST && r_size_1P == {7{1'b0}} && r_AXI4_AWLEN_1P)
						begin
							r_axi4_wrstate_1P	<= s_WR_RESP;
							//r_AXI4_WREADY_c	<= ~r_AXI4_WREADY_c;
							r_AXI4_WLAST_1P		<= 1'b0;
							r_AXI4_BVALID_1P	<= 1'b1;
							
							r_we_1P				<= 1'b1;
							r_last_1P			<= 1'b1;
						end
						else if (r_AXI4_WLAST_1P)
						begin
							r_axi4_wrstate_1P	<= s_WR_RESP;
							//r_AXI4_WREADY_c	<= ~r_AXI4_WREADY_c;
							r_AXI4_WLAST_1P		<= 1'b0;
							r_AXI4_BVALID_1P	<= 1'b1;
							
							r_we_1P				<= 1'b0;
							r_last_1P			<= 1'b0;
						end
					end
				end
			end
			
			s_WR_RESP:
			begin
				r_we_1P		<= 1'b0;
				r_last_1P	<= 1'b0;
				
				if (i_AXI4_BREADY)
				begin
					r_axi4_wrstate_1P	<= s_IDLE;
					r_AXI4_BVALID_1P	<= 1'b0;
				end
			end
		endcase
		
		case (r_axi4_rastate_1P)
			s_INIT:
			begin
				if (w_sdr_init_done)
					r_axi4_rastate_1P	<= s_IDLE;
			end
			
			s_IDLE:
			begin
				if (i_AXI4_ARVALID && r_axi4_nwr_1P
					&& ~r_we_1P && ~w_afull && ~r_AXI4_RVALID_1P)
				begin
					r_axi4_rastate_1P	<= s_RD_ADDR;
					r_AXI4_ARREADY_1P	<= 1'b1;
					r_AXI4_RID_1P		<= i_AXI4_ARID;
					
					r_re_1P				<= 1'b1;
					r_re_lock_1P		<= 1'b1;
					if (i_AXI4_ARLEN == 8'd0 && (SDR_BWIDTH == AXI_RDATA_WIDTH))
						r_last_1P		<= 1'b1;
					
					// TODO AXI different width support
					if (SDR_BWIDTH > AXI_RDATA_WIDTH)
					begin
						r_addr_1P[0+:BA_WIDTH+ROW_WIDTH+COL_WIDTH-(0-SDR_BWIDTH/AXI_RDATA_WIDTH+1)]	<= i_AXI4_ARADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:0-SDR_BWIDTH/AXI_RDATA_WIDTH+1];
					end
					else if (SDR_BWIDTH == AXI_RDATA_WIDTH)
					begin
						r_addr_1P	<= {i_AXI4_ARADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:COL_WIDTH], {(DATA_RATE-1){1'b0}}, i_AXI4_ARADDR[COL_WIDTH-1:DATA_RATE-1]};
						//r_addr_1P	<= {{(DATA_RATE-1){1'b0}},i_AXI4_ARADDR[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:DATA_RATE-1]};
					end
					
					if (SDR_BWIDTH > AXI_WDATA_WIDTH)
					begin
						r_size_1P		<= SDR_BWIDTH/AXI_RDATA_WIDTH-1'b1;
						r_shift_cnt_1P	<= SDR_BWIDTH/AXI_RDATA_WIDTH-1'b1;
						r_addr_cnt_1P	<= SDR_BWIDTH/AXI_RDATA_WIDTH-1'b1;
					end
					else if (SDR_BWIDTH == AXI_WDATA_WIDTH)
					begin
						r_AXI4_ARLEN_1P	<= i_AXI4_ARLEN;
						r_size_1P		<= 7'd0;
						r_shift_cnt_1P	<= 7'd0;
						r_addr_cnt_1P	<= 7'd0;
						r_arlen_cnt_1P	<= i_AXI4_ARLEN;
					end
					else
					begin
						r_AXI4_ARLEN_1P	<= i_AXI4_ARLEN;
						r_size_1P		<= AXI_RDATA_WIDTH/SDR_BWIDTH-1'b1;
						r_shift_cnt_1P	<= AXI_RDATA_WIDTH/SDR_BWIDTH-1'b1;
						r_addr_cnt_1P	<= AXI_RDATA_WIDTH/SDR_BWIDTH-1'b1;
						r_arlen_cnt_1P	<= i_AXI4_ARLEN;
					end
				end
			end
			
			s_RD_ADDR:
			begin
				if (~w_afull)
					r_re_1P	<= 1'b1;
				
				if (w_rd_ack)
				begin
					if (w_afull)
						r_re_1P	<= 1'b0;
					if (SDR_BWIDTH < AXI_WDATA_WIDTH)
						r_addr_1P		<= r_addr_1P+c_addr_increment;
					else if (SDR_BWIDTH == AXI_WDATA_WIDTH)
						r_addr_1P		<= r_addr_1P+c_addr_increment;
					else
						r_addr_1P		<= r_addr_1P+1'b1;
					
					r_addr_cnt_1P	<= r_addr_cnt_1P-1'b1;
					if (r_addr_cnt_1P == 7'd0)
					begin
						r_addr_cnt_1P	<= r_size_1P;
						r_arlen_cnt_1P	<= r_arlen_cnt_1P-1'b1;
					end
					
					if (r_arlen_cnt_1P == 8'd1 && (SDR_BWIDTH == AXI_RDATA_WIDTH))
						r_last_1P	<= 1'b1;
					
					if (r_arlen_cnt_1P == 8'd0)
					begin
						if (r_addr_cnt_1P == 8'd1)
							r_last_1P	<= 1'b1;
						
						if (r_addr_cnt_1P == 8'd0)
						begin
							r_axi4_rastate_1P	<= s_IDLE;
							
							r_re_1P			<= 1'b0;
							r_last_1P		<= 1'b0;
							r_re_lock_1P	<= 1'b0;
						end
					end
				end
			end
		endcase
		
		if (w_rd_valid)
		begin
			if (SDR_BWIDTH >= AXI_RDATA_WIDTH)
			begin
				r_dout_1P[DOUT_WIDTH-1:0]	<= w_dout;
			end
			
			r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH-1:DOUT_WIDTH]	<= r_AXI4_RID[CL+tIORT+1];
			
			r_shift_cnt_1P	<= r_shift_cnt_1P-1'b1;
			
			if (r_shift_cnt_1P == 7'd0)
			begin
				r_fifo_wr_1P	<= 1'b1;
				
				if (arlen_cnt == r_AXI4_ARLEN_1P) begin
			        arlen_cnt   <= {9{1'b0}};
			    end
				else begin
					arlen_cnt	<= arlen_cnt+1'b1;
		        end
		        
		        if (arlen_cnt == r_AXI4_ARLEN_1P)
		            r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH]    <= 1'b1;
		        else
		        	r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH]    <= 1'b0;
				r_shift_cnt_1P	<= r_size_1P;
			end
		end
		
		case (r_axi4_rdstate_1P)
			s_INIT:
			begin
				if (w_sdr_init_done)
					r_axi4_rdstate_1P	<= s_IDLE;
			end
			
			s_IDLE:
			begin
				if (~w_empty & r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH])
				begin
					r_axi4_rdstate_1P	<= s_RD_SHIFT;
					r_fifo_rd_1P		<= 1'b1;
					r_dout_1P[DOUT_WIDTH+AXI_ARID_WIDTH]	<= 1'b0;
				end
			end
			
			s_RD_SHIFT:
			begin
				r_AXI4_RVALID_1P	<= 1'b1;
				
				if (i_AXI4_RREADY)
				begin
					if (w_empty)
					begin
						r_axi4_rdstate_1P	<= s_IDLE;
						r_AXI4_RVALID_1P	<= 1'b0;
					end
				
					if (rd_last)
					begin
						r_axi4_rdstate_1P	<= s_IDLE;
						r_AXI4_RVALID_1P	<= 1'b0;
					end
				end
			end
		endcase
	end
end

genvar i;
generate
	for (i=0; i<CL+tIORT+1; i=i+1)
	begin: pipe
		always@(negedge i_aresetn or posedge i_sysclk)
		begin
			if (~i_aresetn)
				r_AXI4_RID[i+1]	<= {AXI_ARID_WIDTH{1'b0}};
			else
				r_AXI4_RID[i+1]	<= r_AXI4_RID[i];
		end
	end
endgenerate

assign r_AXI4_WREADY_c = w_wr_ack;
assign rd_last = r_AXI4_RVALID_1P ? w_fifo_dout[AXI_RDATA_WIDTH+AXI_ARID_WIDTH] : 1'b0;

assign	o_AXI4_AWREADY	= r_AXI4_AWREADY_1P;
assign	o_AXI4_WREADY	= r_AXI4_WREADY_c;
assign	o_AXI4_BVALID	= r_AXI4_BVALID_1P;
assign	o_AXI4_ARREADY	= r_AXI4_ARREADY_1P;
assign	o_AXI4_RVALID	= r_AXI4_RVALID_1P;
assign	o_AXI4_RDATA	= w_fifo_dout[AXI_RDATA_WIDTH-1:0];
assign	o_AXI4_RLAST	= rd_last;
assign	o_AXI4_BID		= r_AXI4_BID_1P;
assign	o_AXI4_RID		= w_fifo_dout[AXI_RDATA_WIDTH+AXI_ARID_WIDTH-1:AXI_RDATA_WIDTH];
assign	o_AXI4_BRESP	= `OKAY;
assign	o_AXI4_BUSER	= {AXI_BUSER_WIDTH{1'b0}};
assign	o_AXI4_RRESP	= `OKAY;
assign	o_AXI4_RUSER	= {AXI_RUSER_WIDTH{1'b0}};

assign	o_dbg_we			= r_we_1P;
assign	o_dbg_re			= r_re_1P;
assign	o_dbg_last			= r_last_1P;
assign	o_dbg_addr			= r_addr_1P;
assign	o_dbg_din			= r_din_1P;
assign	o_sdr_rd_valid		= w_rd_valid;
assign	o_sdr_dout			= r_dout_1P;
assign	o_axi4_wrstate		= r_axi4_wrstate_1P;
assign	o_dbg_axi4_wlast	= r_AXI4_WLAST_1P;
assign	o_axi4_rastate		= r_axi4_rastate_1P;
assign	o_axi4_rdstate		= r_axi4_rdstate_1P;
assign	o_axi4_nwr			= r_axi4_nwr_1P;
assign	o_re_lock			= r_re_lock_1P;
assign	o_shift_cnt			= r_shift_cnt_1P;
assign	o_axi4_arlen		= r_AXI4_ARLEN_1P;
assign	o_fifo_wr			= r_fifo_wr_1P;
assign	o_fifo_full			= w_afull;
assign	o_fifo_empty		= w_empty;

endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
//////////////////////////////////////////////////////////////////////////////projects/SWIP/hxlai/workplace/test/20201008_184659/testbench_random

/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   axi4.vh
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      axi4 header file
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************
/////////////////////////////////////////////////////////////////////////////

// AxSIZE
`define	BYTES_TX_1		3'b000
`define	BYTES_TX_2		3'b001
`define	BYTES_TX_4		3'b010
`define	BYTES_TX_8		3'b011
`define	BYTES_TX_16		3'b100
`define	BYTES_TX_32		3'b101
`define	BYTES_TX_64		3'b110
`define	BYTES_TX_128	3'b111

// AxBURST
`define	FIXED		2'b00
`define	INCR		2'b01
`define	WRAP		2'b10
`define	RESERVED	2'b11

// xRESP
`define	OKAY	2'b00
`define	EXOKAY	2'b01
`define	SLVERR	2'b10
`define	DECERR	2'b11

// AxCACHE
`define	B_BIT	0
`define	M_BIT	1
`define	OA_BIT	2
`define	A_BIT	3

// AxPROT
`define	PRIVILEGED	0
`define	SECURE		1
`define	DATA_INSTR	2

// AxLOCK
`define	NORMAL		1'b0
`define	EXCLUSIVE	1'b1


/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(dual_clock_fifo_wrapper).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      wraps around dual clock fifo
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************

module `IP_MODULE_NAME(dual_clock_fifo_wrapper)
#(
	parameter	DATA_WIDTH		= 8,
	parameter	ADDR_WIDTH		= 8,
	parameter	LATENCY			= 1,
	parameter	FIFO_MODE		= "STD_FIFO",
	parameter	RAM_INIT_FILE	= "",
	/////////////////////////////////////////////////////////////////////////////////////
	// compatibility	output_reg			check_full_overflow		check_empty_underflow
	/////////////////////////////////////////////////////////////////////////////////////
	// E				user configurable	user configurable		user configurable
	// X				user configurable	always on				always on
	// A				always off			user configurable		user configurable
	parameter	COMPATIBILITY	= "E",
	parameter	OUTPUT_REG		= "TRUE",
	parameter	CHECK_FULL		= "TRUE",
	parameter	CHECK_EMPTY		= "TRUE",
	parameter	AFULL_THRESHOLD	= 2**ADDR_WIDTH-1,
	parameter	AEMPTY_THRESHOLD= 1
)
(
	input						i_arst,
	
	input						i_wclk,
	input						i_we,
	input	[DATA_WIDTH-1:0]	i_wdata,
	
	input						i_rclk,
	input						i_re,
	
	output						o_full,
	output						o_empty,
	output	[DATA_WIDTH-1:0]	o_rdata,
	
	output						o_afull,
	output	[ADDR_WIDTH-1:0]	o_wcnt,
	output						o_aempty,
	output	[ADDR_WIDTH-1:0]	o_rcnt,
	
	output						o_dbg_we,
	output	[ADDR_WIDTH-1:0]	o_dbg_waddr,
	output						o_dbg_re,
	output	[ADDR_WIDTH-1:0]	o_dbg_raddr
);

generate
	if (COMPATIBILITY == "X")
	begin
		if (FIFO_MODE == "BYPASS")
		begin
			`IP_MODULE_NAME(dual_clock_fifo)
			#(
				.DATA_WIDTH			(DATA_WIDTH),
				.ADDR_WIDTH			(ADDR_WIDTH),
				.LATENCY			(LATENCY+4),
				.FIFO_MODE			(FIFO_MODE),
				.RAM_INIT_FILE		(RAM_INIT_FILE),
				.COMPATIBILITY		(COMPATIBILITY),
				.OUTPUT_REG			("FALSE"),
				.CHECK_FULL			("TRUE"),
				.CHECK_EMPTY		("TRUE"),
				.AFULL_THRESHOLD	(AFULL_THRESHOLD),
				.AEMPTY_THRESHOLD	(AEMPTY_THRESHOLD)
			)
			inst_dual_clock_fifo
			(
				.i_arst		(i_arst),
				.i_wclk		(i_wclk),
				.i_we		(i_we),
				.i_wdata	(i_wdata),
				.i_rclk		(i_rclk),
				.i_re		(i_re),
				.o_full		(o_full),
				.o_empty	(o_empty),
				.o_rdata	(o_rdata),
				
				.o_afull	(o_afull),
				.o_wcnt		(o_wcnt),
				.o_aempty	(o_aempty),
				.o_rcnt		(o_rcnt),
				
				.o_dbg_we	(o_dbg_we),
				.o_dbg_waddr(o_dbg_waddr),
				.o_dbg_re	(o_dbg_re),
				.o_dbg_raddr(o_dbg_raddr)
			);
		end
		else
		begin
			`IP_MODULE_NAME(dual_clock_fifo)
			#(
				.DATA_WIDTH			(DATA_WIDTH),
				.ADDR_WIDTH			(ADDR_WIDTH),
				.LATENCY			(LATENCY+2),
				.FIFO_MODE			(FIFO_MODE),
				.RAM_INIT_FILE		(RAM_INIT_FILE),
				.COMPATIBILITY		(COMPATIBILITY),
				.OUTPUT_REG			(OUTPUT_REG),
				.CHECK_FULL			("TRUE"),
				.CHECK_EMPTY		("TRUE"),
				.AFULL_THRESHOLD	(AFULL_THRESHOLD),
				.AEMPTY_THRESHOLD	(AEMPTY_THRESHOLD)
			)
			inst_dual_clock_fifo
			(
				.i_arst		(i_arst),
				.i_wclk		(i_wclk),
				.i_we		(i_we),
				.i_wdata	(i_wdata),
				.i_rclk		(i_rclk),
				.i_re		(i_re),
				.o_full		(o_full),
				.o_empty	(o_empty),
				.o_rdata	(o_rdata),
				
				.o_afull	(o_afull),
				.o_wcnt		(o_wcnt),
				.o_aempty	(o_aempty),
				.o_rcnt		(o_rcnt),
				
				.o_dbg_we	(o_dbg_we),
				.o_dbg_waddr(o_dbg_waddr),
				.o_dbg_re	(o_dbg_re),
				.o_dbg_raddr(o_dbg_raddr)
			);
		end
	end
	else if (COMPATIBILITY == "A")
	begin
		`IP_MODULE_NAME(dual_clock_fifo)
		#(
			.DATA_WIDTH			(DATA_WIDTH),
			.ADDR_WIDTH			(ADDR_WIDTH),
			.LATENCY			(LATENCY),
			.FIFO_MODE			(FIFO_MODE),
			.RAM_INIT_FILE		(RAM_INIT_FILE),
			.COMPATIBILITY		(COMPATIBILITY),
			.OUTPUT_REG			("FALSE"),
			.CHECK_FULL			(CHECK_FULL),
			.CHECK_EMPTY		(CHECK_EMPTY),
			.AFULL_THRESHOLD	(AFULL_THRESHOLD),
			.AEMPTY_THRESHOLD	(AEMPTY_THRESHOLD)
		)
		inst_dual_clock_fifo
		(
			.i_arst		(i_arst),
			.i_wclk		(i_wclk),
			.i_we		(i_we),
			.i_wdata	(i_wdata),
			.i_rclk		(i_rclk),
			.i_re		(i_re),
			.o_full		(o_full),
			.o_empty	(o_empty),
			.o_rdata	(o_rdata),
			
			.o_afull	(o_afull),
			.o_wcnt		(o_wcnt),
			.o_aempty	(o_aempty),
			.o_rcnt		(o_rcnt),
			
			.o_dbg_we	(o_dbg_we),
			.o_dbg_waddr(o_dbg_waddr),
			.o_dbg_re	(o_dbg_re),
			.o_dbg_raddr(o_dbg_raddr)
		);
	end
	else
	begin
		`IP_MODULE_NAME(dual_clock_fifo)
		#(
			.DATA_WIDTH			(DATA_WIDTH),
			.ADDR_WIDTH			(ADDR_WIDTH),
			.LATENCY			(LATENCY),
			.FIFO_MODE			(FIFO_MODE),
			.RAM_INIT_FILE		(RAM_INIT_FILE),
			.COMPATIBILITY		(COMPATIBILITY),
			.OUTPUT_REG			(OUTPUT_REG),
			.CHECK_FULL			(CHECK_FULL),
			.CHECK_EMPTY		(CHECK_EMPTY),
			.AFULL_THRESHOLD	(AFULL_THRESHOLD),
			.AEMPTY_THRESHOLD	(AEMPTY_THRESHOLD)
		)
		inst_dual_clock_fifo
		(
			.i_arst		(i_arst),
			.i_wclk		(i_wclk),
			.i_we		(i_we),
			.i_wdata	(i_wdata),
			.i_rclk		(i_rclk),
			.i_re		(i_re),
			.o_full		(o_full),
			.o_empty	(o_empty),
			.o_rdata	(o_rdata),
			
			.o_afull	(o_afull),
			.o_wcnt		(o_wcnt),
			.o_aempty	(o_aempty),
			.o_rcnt		(o_rcnt),
			
			.o_dbg_we	(o_dbg_we),
			.o_dbg_waddr(o_dbg_waddr),
			.o_dbg_re	(o_dbg_re),
			.o_dbg_raddr(o_dbg_raddr)
		);
	end
endgenerate

endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(dual_clock_fifo).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      dual clock fifo
//  /_/ /\ \_____/ /     
// ____/  \_______/     
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************
/////////////////////////////////////////////////////////////////////////////

module `IP_MODULE_NAME(dual_clock_fifo)
#(
	parameter	DATA_WIDTH		= 8,
	parameter	ADDR_WIDTH		= 8,
	parameter	LATENCY			= 1,
	parameter	FIFO_MODE		= "STD_FIFO",
	parameter	RAM_INIT_FILE	= "",
	parameter	COMPATIBILITY	= "E",
	parameter	OUTPUT_REG		= "FALSE",
	parameter	CHECK_FULL		= "TRUE",
	parameter	CHECK_EMPTY		= "TRUE",
	parameter	AFULL_THRESHOLD	= 2**ADDR_WIDTH-1,
	parameter	AEMPTY_THRESHOLD= 1
)
(
	input						i_arst,
	
	input						i_wclk,
	input						i_we,
	input	[DATA_WIDTH-1:0]	i_wdata,
	
	input						i_rclk,
	input						i_re,
	
	output						o_full,
	output						o_empty,
	output	[DATA_WIDTH-1:0]	o_rdata,
	
	output						o_afull,
	output	[ADDR_WIDTH-1:0]	o_wcnt,
	output						o_aempty,
	output	[ADDR_WIDTH-1:0]	o_rcnt,
	
	output						o_dbg_we,
	output	[ADDR_WIDTH-1:0]	o_dbg_waddr,
	output						o_dbg_re,
	output	[ADDR_WIDTH-1:0]	o_dbg_raddr
);

reg		[ADDR_WIDTH:0]	r_waddrb_1P;
reg						r_wflag_1P;
reg		[ADDR_WIDTH-1:0]r_waddrg_1P;
reg		[ADDR_WIDTH-1:0]r_waddrg_2P;

reg		[ADDR_WIDTH:0]r_raddrb_wclk_1P;
reg		[ADDR_WIDTH:0]r_raddrb_wclk_neg;
reg		[ADDR_WIDTH:0]wr_cnt;

reg		[ADDR_WIDTH:0]r_waddrb_rclk_1P;
reg		[ADDR_WIDTH:0]r_waddrb_rclk_neg;
reg		[ADDR_WIDTH:0]rd_cnt;

reg						r_we_1P;
reg						r_re_1P;
reg		[ADDR_WIDTH:0]	r_raddrb_1P;
reg						r_rflag_1P;
reg		[ADDR_WIDTH-1:0]r_raddrg_1P;
reg						r_rflag_2P;
reg		[ADDR_WIDTH-1:0]r_raddrg_2P;

reg		[LATENCY-1:0]	r_empty;
reg		[LATENCY:0]		r_full;

wire	[ADDR_WIDTH:0]	w_waddrb_1P;
wire					w_wflag_1P;
wire	[ADDR_WIDTH-1:0]w_waddrg_1P;

wire	[ADDR_WIDTH:0]	w_raddrb_1P;
wire					w_rflag_1P;
wire	[ADDR_WIDTH-1:0]w_raddrg_1P;

wire	w_empty;
wire	w_full;

wire	w_empty_P;
wire	w_full_P;

wire					w_we;
wire					w_re;
wire	[ADDR_WIDTH-1:0]w_raddr;

assign	w_waddrb_1P					=	r_waddrb_1P + 1'b1;
assign	w_wflag_1P					=	w_waddrb_1P[ADDR_WIDTH];
assign	w_waddrg_1P[ADDR_WIDTH-1]	=	w_waddrb_1P[ADDR_WIDTH-1] ^ 1'b0;
assign	w_waddrg_1P[ADDR_WIDTH-2:0]	=	w_waddrb_1P[ADDR_WIDTH-2:0] ^ w_waddrb_1P[ADDR_WIDTH-1:1];

assign	w_full	=	((r_waddrg_1P == r_raddrg_1P) &
					(r_wflag_1P != r_rflag_1P))?
						1'b1:
					(i_we &
					((w_waddrg_1P == r_raddrg_2P) &
					(w_wflag_1P != r_rflag_2P)))?
						1'b1:
						1'b0;

always@(posedge i_arst or posedge i_wclk)
begin
	if (i_arst) begin
		r_raddrb_wclk_1P	<= {ADDR_WIDTH+1{1'b0}};
	end
	else begin
		r_raddrb_wclk_1P	<= r_raddrb_1P;
	end
end

always@(posedge i_arst or posedge i_wclk)
begin
	if (i_arst) begin
		r_raddrb_wclk_neg	<= {ADDR_WIDTH+1{1'b0}};
	end
	else begin
		r_raddrb_wclk_neg	<= ~r_raddrb_wclk_1P + 1'b1;
	end
end

always@(posedge i_arst or posedge i_wclk)
begin
	if (i_arst) begin
		wr_cnt			<= {ADDR_WIDTH+1{1'b0}};
	end
	else begin
		wr_cnt			<= r_waddrb_1P + r_raddrb_wclk_neg;
	end
end

always@(posedge i_arst or posedge i_rclk)
begin
	if (i_arst) begin
		r_waddrb_rclk_1P	<= {ADDR_WIDTH+1{1'b0}};
	end
	else begin
		r_waddrb_rclk_1P	<= r_waddrb_1P;
	end
end

always@(posedge i_arst or posedge i_rclk)
begin
	if (i_arst) begin
		r_waddrb_rclk_neg	<= {ADDR_WIDTH+1{1'b0}};
	end
	else begin
		r_waddrb_rclk_neg	<= ~r_waddrb_rclk_1P;
	end
end

always@(posedge i_arst or posedge i_rclk)
begin
	if (i_arst) begin
		rd_cnt			<= {ADDR_WIDTH+1{1'b0}};
	end
	else begin
		rd_cnt			<= r_raddrb_1P + r_waddrb_rclk_neg;
	end
end

always@(posedge i_arst or posedge i_wclk)
begin
	if (i_arst)
	begin
		r_we_1P			<= 1'b0;
		r_waddrb_1P		<= {ADDR_WIDTH{1'b0}};
		r_wflag_1P		<= 1'b0;
		r_waddrg_1P		<= {ADDR_WIDTH{1'b0}};
		r_waddrg_2P		<= {ADDR_WIDTH{1'b0}};
		
		r_full[0]		<= 1'b0;
	end
	else
	begin
		r_we_1P	<= 1'b0;

		if (CHECK_FULL == "TRUE")
		begin
			if (i_we & ~w_full_P)
			begin
				r_we_1P			<= 1'b1;
				r_waddrb_1P		<= w_waddrb_1P;
				r_wflag_1P		<= w_wflag_1P;
				r_waddrg_1P		<= w_waddrg_1P;
			end
		end
		else
		begin
			if (i_we)
			begin
				r_we_1P			<= 1'b1;
				r_waddrb_1P		<= w_waddrb_1P;
				r_wflag_1P		<= w_wflag_1P;
				r_waddrg_1P		<= w_waddrg_1P;
			end
		end
		
		if (r_we_1P)
			r_waddrg_2P		<= r_waddrg_1P;
		
		r_full[0]		<= w_full;
	end
end

assign	w_raddrb_1P					=	r_raddrb_1P + 1'b1;
assign	w_rflag_1P					=	w_raddrb_1P[ADDR_WIDTH];
assign	w_raddrg_1P[ADDR_WIDTH-1]	=	w_raddrb_1P[ADDR_WIDTH-1] ^ 1'b0;
assign	w_raddrg_1P[ADDR_WIDTH-2:0]	=	w_raddrb_1P[ADDR_WIDTH-2:0] ^ w_raddrb_1P[ADDR_WIDTH-1:1];

assign	w_empty	=	((r_waddrg_2P == r_raddrg_1P) &
					(r_wflag_1P == r_rflag_2P))?
						1'b1:
					(i_re &
					((r_waddrg_1P == r_raddrg_1P) &
					(r_wflag_1P == r_rflag_1P)))?
						1'b1:
						1'b0;

always@(posedge i_arst or posedge i_rclk)
begin
	if (i_arst)
	begin
		r_re_1P			<= 1'b0;
		r_raddrb_1P		<= {ADDR_WIDTH{1'b0}};
		r_rflag_1P		<= 1'b0;
		r_raddrg_1P		<= {ADDR_WIDTH{1'b0}};
		r_rflag_2P		<= 1'b0;
		r_raddrg_2P		<= {ADDR_WIDTH{1'b0}};
		
		r_empty[0]		<= 1'b1;
	end
	else
	begin
		r_re_1P	<= 1'b0;
		
		if (CHECK_FULL == "TRUE")
		begin
			if (i_re & ~w_empty_P)
			begin
				r_re_1P			<= 1'b1;
				r_raddrb_1P		<= w_raddrb_1P;
				r_rflag_1P		<= w_rflag_1P;
				r_raddrg_1P		<= w_raddrg_1P;
			end
		end
		else
		begin
			if (i_re)
			begin
				r_re_1P			<= 1'b1;
				r_raddrb_1P		<= w_raddrb_1P;
				r_rflag_1P		<= w_rflag_1P;
				r_raddrg_1P		<= w_raddrg_1P;
			end
		end
		
		if (r_re_1P)
		begin
			r_raddrg_2P		<= r_raddrg_1P;
			r_rflag_2P		<= r_rflag_1P;
		end
		
		r_empty[0]		<= w_empty;
	end
end

genvar i, j;
generate
	for (i=1; i<LATENCY; i=i+1)
	begin: pipe_empty
		always@(posedge i_arst or posedge i_rclk)
		begin
			if (i_arst)
				r_empty[i]	<= 1'b1;
			else
				r_empty[i]	<= r_empty[i-1];
		end
	end
	
	assign	w_empty_P	= w_empty | r_empty[LATENCY-1];
	
	for (j=1; j<LATENCY+1; j=j+1)
	begin: pipe_full
		always@(posedge i_arst or posedge i_wclk)
		begin
			if (i_arst)
				r_full[j]	<= 1'b0;
			else
				r_full[j]	<= r_full[j-1];
		end
	end
	
	if (COMPATIBILITY == "X")
		if (FIFO_MODE == "BYPASS")
			assign	w_full_P	= r_full[0] | r_full[LATENCY-2];
		else
			assign	w_full_P	= r_full[0]	| r_full[LATENCY];
	else
		assign	w_full_P	= r_full[0] | r_full[LATENCY-1];
	
	if (CHECK_FULL == "TRUE")
		assign	w_we	= i_we & ~w_full_P;
	else
		assign	w_we	= i_we;
	
	if (FIFO_MODE == "BYPASS")
	begin
		assign	w_re	= 1'b1;
		if (CHECK_EMPTY == "TRUE")
			assign	w_raddr	= (i_re & ~w_empty_P)?
								w_raddrg_1P[ADDR_WIDTH-1:0]:
								r_raddrg_1P[ADDR_WIDTH-1:0];
		else
			assign	w_raddr	= (i_re)?
								w_raddrg_1P[ADDR_WIDTH-1:0]:
								r_raddrg_1P[ADDR_WIDTH-1:0];
	end
	else
	begin
		if (CHECK_EMPTY == "TRUE")
			assign	w_re	= i_re & ~w_empty_P;
		else
			assign	w_re	= i_re;
		assign	w_raddr	= r_raddrg_1P[ADDR_WIDTH-1:0];
	end

	`IP_MODULE_NAME(sdram_simple_dual_port_ram)
	#(
		.DATA_WIDTH(DATA_WIDTH),
		.ADDR_WIDTH(ADDR_WIDTH),
		.OUTPUT_REG(OUTPUT_REG),
		.RAM_INIT_FILE(RAM_INIT_FILE)
	)
	inst_simple_dual_port_ram
	(
		.wdata(i_wdata),
		.waddr(r_waddrg_1P[ADDR_WIDTH-1:0]),
		.raddr(w_raddr),
		.we(w_we),
		.wclk(i_wclk),
		.re(w_re),
		.rclk(i_rclk),
		.rdata(o_rdata)
	);
endgenerate

assign	o_empty	= w_empty_P;
assign	o_full	= w_full_P;

assign	o_aempty= w_empty_P | (rd_cnt[ADDR_WIDTH-1] & rd_cnt[ADDR_WIDTH-2] & rd_cnt[ADDR_WIDTH-3]);
assign	o_wcnt	= wr_cnt[ADDR_WIDTH] ? {ADDR_WIDTH{1'b1}} : wr_cnt[ADDR_WIDTH-1:0];
assign	o_afull	= w_full_P | wr_cnt[ADDR_WIDTH] | (wr_cnt[ADDR_WIDTH-1] & wr_cnt[ADDR_WIDTH-2] & wr_cnt[ADDR_WIDTH-3]);
assign	o_rcnt	= w_full_P ? {ADDR_WIDTH{1'b0}} : rd_cnt[ADDR_WIDTH-1:0];

assign	o_dbg_we	= w_we;
assign	o_dbg_waddr	= r_waddrg_1P[ADDR_WIDTH-1:0];
assign	o_dbg_re	= w_re;
assign	o_dbg_raddr	= w_raddr;

endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
/////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(efx_sdram_controller).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      SDRAM controller top module
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************

module `IP_MODULE_NAME(efx_sdram_controller)
(
	i_aresetn,
	i_arst,
	i_sysclk,
	i_sdrclk,
	i_tACclk,
	i_pll_locked,
	o_pll_reset,
	i_we,
	i_re,
	i_last,
	i_addr,
	i_din,
        i_dm,
	o_dout,
	o_sdr_init_done,
	o_wr_ack,
	o_rd_ack,
	o_ref_req,
	o_rd_valid,
	o_AXI4_AWREADY,
	i_AXI4_AWADDR,
	i_AXI4_AWPROT,
	i_AXI4_AWVALID,
	o_AXI4_WREADY,
	i_AXI4_WDATA,
	i_AXI4_WLAST,
	i_AXI4_WVALID,
	o_AXI4_BVALID,
	i_AXI4_BREADY,
	o_AXI4_ARREADY,
	i_AXI4_ARADDR,
	i_AXI4_ARPROT,
    i_AXI4_ARVALID,
	i_AXI4_RREADY,
	o_AXI4_RDATA,
	o_AXI4_RLAST,
	o_AXI4_RVALID,
	i_AXI4_AWID,
	i_AXI4_AWREGION,
	i_AXI4_AWLEN,
	i_AXI4_AWSIZE,
	i_AXI4_AWBURST,
	i_AXI4_AWLOCK,
	i_AXI4_AWCACHE,
	i_AXI4_AWQOS,
	i_AXI4_AWUSER,
	i_AXI4_WSTRB,
	i_AXI4_WUSER,
	o_AXI4_BID,
	o_AXI4_BRESP,					
	o_AXI4_BUSER,	
	i_AXI4_ARID,
	i_AXI4_ARREGION,				
	i_AXI4_ARLEN,
	i_AXI4_ARSIZE,
	i_AXI4_ARBURST,					
	i_AXI4_ARLOCK,							
	i_AXI4_ARCACHE,				
	i_AXI4_ARQOS,					
	i_AXI4_ARUSER,	
	o_AXI4_RID,
	o_AXI4_RRESP,						
	o_AXI4_RUSER,
	o_sdr_CKE,
	o_sdr_n_CS,
	o_sdr_n_RAS,
	o_sdr_n_CAS,
	o_sdr_n_WE,
	o_sdr_BA,
	o_sdr_ADDR,
	o_sdr_DATA,
	o_sdr_DATA_oe,
	i_sdr_DATA,
	o_sdr_DQM,
	o_dbg_dly_cnt_b,
	o_dbg_tRCD_done,
	o_dbg_tRTW_done,
	o_dbg_ref_req,
	o_dbg_wr_ack,
	o_dbg_rd_ack,
	o_sdr_state,
	o_dbg_we,
	o_dbg_re,
	o_dbg_last,
	o_dbg_addr,
	o_dbg_din,
	o_sdr_rd_valid,
	o_sdr_dout,
	o_axi4_wrstate,
	o_dbg_axi4_wlast,
	o_axi4_rastate,
	o_axi4_rdstate,
	o_axi4_nwr,
	o_re_lock,
	o_shift_cnt,
	o_axi4_arlen,
	o_fifo_wr,
	o_fifo_full,
	o_fifo_empty,
	o_dbg_fifo_we,
	o_dbg_fifo_waddr,
	o_dbg_fifo_re,
	o_dbg_fifo_raddr,
    o_dbg_n_CS,
    o_dbg_n_RAS,
    o_dbg_n_CAS,
    o_dbg_n_WE,
    o_dbg_BA,
    o_dbg_ADDR,
    o_dbg_DATA_out,
    o_dbg_DATA_in
);

	parameter	AXI_AWADDR_WIDTH	= 25;
	parameter	AXI_WDATA_WIDTH		= 64;
	parameter	AXI_ARADDR_WIDTH	= 25;
	parameter	AXI_RDATA_WIDTH		= 64;
                                    
	parameter	fSYS_MHz		= 100;
	parameter	fCK_MHz			= 200;
	parameter   DATA_RATE       = 2;
	parameter	DDIO_TYPE		= "SOFT";
	parameter	tPWRUP			= 200000;			// 100 us
	parameter	tRAS			= 44;			// 44 ns
	parameter	tRAS_MAX		= 120000;		// 120 us
	parameter	tRC			    = 66;			// 66 ns
	parameter	tRCD			= 20;			// 20 ns
	parameter	tREF			= 64000000;			// 64 ms
	parameter	tRFC			= 66;			// 66 ns
	parameter	tRP			    = 20;			// 20 ns
	parameter	tWR			    = 2;			// 1 CK+7.5 ns
	parameter	tMRD			= 2;			// 2 CK
	parameter	CL			    = 3;			// 3 CK
	parameter	BL			    = 1;
    parameter   tIORT_u		    = 2;
	parameter	BA_WIDTH		= 2;
	parameter	ROW_WIDTH		= 13;
	parameter	COL_WIDTH		= 10;
	parameter	DQ_WIDTH		= 8;	// x4; x8
	parameter	DQ_GROUP		= 4;
	parameter   SDRAM_MODE      = "AXI4";
	
	//----- parameter not configurable by user----
	parameter	AXI_AWID_WIDTH		= 4;
	parameter	AXI_AWUSER_WIDTH	= 2;
	parameter	AXI_WUSER_WIDTH		= 2;
	parameter	AXI_BID_WIDTH		= 4;
	parameter	AXI_BUSER_WIDTH		= 2;
	parameter	AXI_ARID_WIDTH		= 4;
	parameter	AXI_ARUSER_WIDTH	= 3;
	parameter	AXI_RUSER_WIDTH		= 3;
	
	//Common
	input i_aresetn;
	input i_arst;
	input i_sysclk;
	input i_sdrclk;
	input i_tACclk;
	input i_pll_locked;
	output	o_pll_reset;
	
	//Native 
	input	i_we;
	input	i_re;
	input	i_last;
	input	[(BA_WIDTH+ROW_WIDTH+COL_WIDTH)	-1:0]				i_addr;
	input	[DATA_RATE	*DQ_GROUP		*DQ_WIDTH		-1:0]	i_din;
        input   [(DATA_RATE     *DQ_GROUP               *DQ_WIDTH)/8    -1:0]           i_dm;
	output	[DATA_RATE	*DQ_GROUP		*DQ_WIDTH		-1:0]	o_dout;
	output	o_sdr_init_done;
	output	o_wr_ack;
	output	o_rd_ack;
	output	o_ref_req;
	output	o_rd_valid;
	
	//AXI4
	output wire o_AXI4_AWREADY;
	input  	[AXI_AWADDR_WIDTH-1:0] i_AXI4_AWADDR;
	input  	[2:0] i_AXI4_AWPROT;
	input  	i_AXI4_AWVALID;
	
	output 	o_AXI4_WREADY;
	input  	[AXI_WDATA_WIDTH-1:0] i_AXI4_WDATA;
	input  	i_AXI4_WLAST;
	input  	i_AXI4_WVALID;
	
	output 	o_AXI4_BVALID;
	input 	i_AXI4_BREADY;
	
	output 	o_AXI4_ARREADY;
	input 	[AXI_ARADDR_WIDTH-1:0] i_AXI4_ARADDR;
	input 	[2:0] i_AXI4_ARPROT;
    input 	i_AXI4_ARVALID;
	
	input 	i_AXI4_RREADY;
	output	[AXI_RDATA_WIDTH-1:0] o_AXI4_RDATA;
	output 	o_AXI4_RLAST;
	output  o_AXI4_RVALID;
	
	input	[AXI_AWID_WIDTH-1:0] i_AXI4_AWID;
	input	[3:0] i_AXI4_AWREGION;
	input	[7:0] i_AXI4_AWLEN;
	input	[2:0] i_AXI4_AWSIZE;
	input	[1:0] i_AXI4_AWBURST;
	input  	i_AXI4_AWLOCK;
	input	[3:0] i_AXI4_AWCACHE;
	input	[3:0] i_AXI4_AWQOS;
	input	[AXI_AWUSER_WIDTH-1:0] i_AXI4_AWUSER;
	input	[AXI_WDATA_WIDTH/8-1:0] i_AXI4_WSTRB;
	input	[AXI_WUSER_WIDTH-1:0] i_AXI4_WUSER;
	
	output	[AXI_BID_WIDTH-1:0] o_AXI4_BID;
	output	[1:0] o_AXI4_BRESP;					
	output	[AXI_BUSER_WIDTH-1:0] o_AXI4_BUSER;	
	
	input	[AXI_ARID_WIDTH-1:0] i_AXI4_ARID;
	input	[3:0] i_AXI4_ARREGION;				
	input	[7:0] i_AXI4_ARLEN;
	input	[2:0] i_AXI4_ARSIZE;
	input	[1:0] i_AXI4_ARBURST;					
	input	i_AXI4_ARLOCK;							
	input	[3:0] i_AXI4_ARCACHE;				
	input	[3:0] i_AXI4_ARQOS;					
	input	[AXI_ARUSER_WIDTH-1:0] i_AXI4_ARUSER;	
	
	output	[AXI_ARID_WIDTH-1:0] o_AXI4_RID;
	output	[1:0] o_AXI4_RRESP;						
	output	[AXI_RUSER_WIDTH-1:0] o_AXI4_RUSER;
	
	output	[DATA_RATE							-1:0]	o_sdr_CKE;
	output	[DATA_RATE							-1:0]	o_sdr_n_CS;
	output	[DATA_RATE							-1:0]	o_sdr_n_RAS;
	output	[DATA_RATE							-1:0]	o_sdr_n_CAS;
	output	[DATA_RATE							-1:0]	o_sdr_n_WE;
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_sdr_BA;
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_sdr_ADDR;
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA;
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA_oe;
	input	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	i_sdr_DATA;
	output	[DATA_RATE	*DQ_GROUP				-1:0]	o_sdr_DQM;
	
	// Debug port
	output	[5:0] o_dbg_dly_cnt_b;
	output	o_dbg_tRCD_done;
	output	o_dbg_tRTW_done;
	output	o_dbg_ref_req;
	output	o_dbg_wr_ack;
	output	o_dbg_rd_ack;
	output	[3:0] o_sdr_state;
	output	o_dbg_we;
	output	o_dbg_re;
	output	o_dbg_last;
	output	[BA_WIDTH+ROW_WIDTH+COL_WIDTH-1:0] o_dbg_addr;
	output	[AXI_WDATA_WIDTH-1:0] o_dbg_din;
	output	o_sdr_rd_valid;
	output	[DATA_RATE*DQ_GROUP*DQ_WIDTH+AXI_ARID_WIDTH:0] o_sdr_dout;
	output	[1:0] o_axi4_wrstate;
	output	o_dbg_axi4_wlast;
	output	[1:0] o_axi4_rastate;
	output	[1:0] o_axi4_rdstate;
	output	o_axi4_nwr;
	output	o_re_lock;
	output	[6:0] o_shift_cnt;
	output	[7:0] o_axi4_arlen;
	output	o_fifo_wr;
	output	o_fifo_full;
	output	o_fifo_empty;
	output	o_dbg_fifo_we;
	output	[7:0] o_dbg_fifo_waddr;
	output	o_dbg_fifo_re;
	output	[7:0] o_dbg_fifo_raddr;
	
	output	[DATA_RATE							-1:0]	o_dbg_n_CS;
	output	[DATA_RATE							-1:0]	o_dbg_n_RAS;
	output	[DATA_RATE							-1:0]	o_dbg_n_CAS;
	output	[DATA_RATE							-1:0]	o_dbg_n_WE;
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_dbg_BA;
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_dbg_ADDR;
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_dbg_DATA_out;
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_dbg_DATA_in;
	
generate
   if (SDRAM_MODE == "AXI4") begin
   `IP_MODULE_NAME(axi4_sdram_controller)
   #(
	.AXI_AWADDR_WIDTH	(AXI_AWADDR_WIDTH),
	.AXI_WDATA_WIDTH	(AXI_WDATA_WIDTH),
	.AXI_ARADDR_WIDTH	(AXI_ARADDR_WIDTH),
	.AXI_RDATA_WIDTH	(AXI_RDATA_WIDTH),
	.fSYS_MHz			(fSYS_MHz),
	.fCK_MHz			(fCK_MHz),
	.DDIO_TYPE	        (DDIO_TYPE),
	.tPWRUP		        (tPWRUP),
	.tRAS		        (tRAS),
	.tRAS_MAX	        (tRAS_MAX),
	.tRC		        (tRC),
	.tRCD		        (tRCD),
	.tREF		        (tREF),
	.tRFC		        (tRFC),
	.tRP		        (tRP),
	.tWR		        (tWR),
	.tMRD		        (tMRD),
	.CL			        (CL),
	.BL			        (BL),
	.DATA_RATE          (DATA_RATE),
	.tIORT_u		    (tIORT_u),
	.BA_WIDTH	        (BA_WIDTH),
	.ROW_WIDTH	        (ROW_WIDTH),
	.COL_WIDTH	        (COL_WIDTH),
	.DQ_WIDTH	        (DQ_WIDTH),
	.DQ_GROUP	        (DQ_GROUP),
    .AXI_AWID_WIDTH	    (AXI_AWID_WIDTH	     ),
    .AXI_AWUSER_WIDTH   (AXI_AWUSER_WIDTH    ),
    .AXI_WUSER_WIDTH	(AXI_WUSER_WIDTH	 ),
    .AXI_BID_WIDTH	    (AXI_BID_WIDTH	     ),
    .AXI_BUSER_WIDTH	(AXI_BUSER_WIDTH	 ),
    .AXI_ARID_WIDTH	    (AXI_ARID_WIDTH	     ),
    .AXI_ARUSER_WIDTH   (AXI_ARUSER_WIDTH    ),
    .AXI_RUSER_WIDTH	(AXI_RUSER_WIDTH	 )
	)
	inst_axi4_sdram_controller
	(
	.i_aresetn			(i_aresetn),
	.i_sysclk			(i_sysclk),
	.i_sdrclk			(i_sdrclk),
	.i_tACclk			(i_tACclk),
	.i_pll_locked		(i_pll_locked),
	
	.o_AXI4_AWREADY		(o_AXI4_AWREADY),
	.i_AXI4_AWADDR		(i_AXI4_AWADDR),
	.i_AXI4_AWPROT		(i_AXI4_AWPROT),
	.i_AXI4_AWVALID		(i_AXI4_AWVALID),
	
	.o_AXI4_WREADY		(o_AXI4_WREADY),
	.i_AXI4_WDATA		(i_AXI4_WDATA),
	.i_AXI4_WLAST		(i_AXI4_WLAST),
	.i_AXI4_WVALID		(i_AXI4_WVALID),
	
	.o_AXI4_BVALID		(o_AXI4_BVALID),
	.i_AXI4_BREADY		(i_AXI4_BREADY),
	
	.o_AXI4_ARREADY		(o_AXI4_ARREADY),
	.i_AXI4_ARADDR		(i_AXI4_ARADDR),
	.i_AXI4_ARPROT		(i_AXI4_ARPROT),
	.i_AXI4_ARVALID		(i_AXI4_ARVALID),
	
	.i_AXI4_RREADY		(i_AXI4_RREADY),
	.o_AXI4_RDATA		(o_AXI4_RDATA),
	.o_AXI4_RLAST		(o_AXI4_RLAST),
	.o_AXI4_RVALID		(o_AXI4_RVALID),
	
	.i_AXI4_AWID		(i_AXI4_AWID),
	.i_AXI4_AWREGION	(i_AXI4_AWREGION),
	.i_AXI4_AWLEN		(i_AXI4_AWLEN),
	.i_AXI4_AWSIZE		(i_AXI4_AWSIZE),
	.i_AXI4_AWBURST		(i_AXI4_AWBURST),
	.i_AXI4_AWLOCK		(i_AXI4_AWLOCK),
	.i_AXI4_AWCACHE		(i_AXI4_AWCACHE),
	.i_AXI4_AWQOS		(i_AXI4_AWQOS),
	.i_AXI4_AWUSER		(i_AXI4_AWUSER),
	
	.i_AXI4_WSTRB		(i_AXI4_WSTRB),
	.i_AXI4_WUSER		(i_AXI4_WUSER),
	
	.o_AXI4_BID			(o_AXI4_BID),
	.o_AXI4_BRESP		(o_AXI4_BRESP),
	.o_AXI4_BUSER		(o_AXI4_BUSER),
	
	.i_AXI4_ARID		(i_AXI4_ARID),
	.i_AXI4_ARREGION	(i_AXI4_ARREGION),
	.i_AXI4_ARLEN		(i_AXI4_ARLEN),
	.i_AXI4_ARSIZE		(i_AXI4_ARSIZE),
	.i_AXI4_ARBURST		(i_AXI4_ARBURST),
	.i_AXI4_ARLOCK		(i_AXI4_ARLOCK),
	.i_AXI4_ARCACHE		(i_AXI4_ARCACHE),
	.i_AXI4_ARQOS		(i_AXI4_ARQOS),
	.i_AXI4_ARUSER		(i_AXI4_ARUSER),
	
	.o_AXI4_RID			(o_AXI4_RID),
	.o_AXI4_RRESP		(o_AXI4_RRESP),
	.o_AXI4_RUSER		(o_AXI4_RUSER),
	
	.o_sdr_CKE			(o_sdr_CKE),
	.o_sdr_n_CS			(o_sdr_n_CS),
	.o_sdr_n_RAS		(o_sdr_n_RAS),
	.o_sdr_n_CAS		(o_sdr_n_CAS),
	.o_sdr_n_WE			(o_sdr_n_WE),
	.o_sdr_BA			(o_sdr_BA),
	.o_sdr_ADDR			(o_sdr_ADDR),
	.o_sdr_DATA			(o_sdr_DATA),
	.o_sdr_DATA_oe		(o_sdr_DATA_oe),
	.i_sdr_DATA			(i_sdr_DATA),
	.o_sdr_DQM			(o_sdr_DQM),
	
	.o_sdr_state		(o_sdr_state),
	.o_dbg_we			(o_dbg_we),
	.o_dbg_re			(o_dbg_re),
	.o_dbg_last			(o_dbg_last),
	.o_dbg_addr			(o_dbg_addr),
	.o_dbg_din			(o_dbg_din),
	.o_dbg_wr_ack		(o_dbg_wr_ack),
	.o_dbg_rd_ack		(o_dbg_rd_ack),
	.o_sdr_rd_valid		(o_sdr_rd_valid),
	.o_dbg_ref_req		(o_dbg_ref_req),
	.o_sdr_dout			(o_sdr_dout),
	.o_axi4_wrstate		(o_axi4_wrstate),
	.o_dbg_axi4_wlast	(o_dbg_axi4_wlast),
	.o_axi4_rastate		(o_axi4_rastate),
	.o_axi4_rdstate		(o_axi4_rdstate),
	.o_axi4_nwr			(o_axi4_nwr),
	.o_re_lock			(o_re_lock),
	.o_shift_cnt		(o_shift_cnt),
	.o_axi4_arlen		(o_axi4_arlen),
	.o_fifo_wr			(o_fifo_wr),
	.o_fifo_full		(o_fifo_full),
	.o_fifo_empty		(o_fifo_empty),
	.o_dbg_fifo_we		(o_dbg_fifo_we),
	.o_dbg_fifo_waddr	(o_dbg_fifo_waddr),
	.o_dbg_fifo_re		(o_dbg_fifo_re),
	.o_dbg_fifo_raddr	(o_dbg_fifo_raddr),
	
	.o_dbg_n_CS			(o_dbg_n_CS),
	.o_dbg_n_RAS		(o_dbg_n_RAS),
	.o_dbg_n_CAS		(o_dbg_n_CAS),
	.o_dbg_n_WE			(o_dbg_n_WE),
	.o_dbg_BA			(o_dbg_BA),
	.o_dbg_ADDR			(o_dbg_ADDR),
	.o_dbg_DATA_out		(o_dbg_DATA_out),
	.o_dbg_DATA_in		(o_dbg_DATA_in)
);
end
else begin
`IP_MODULE_NAME(sdram_controller)
#(
	.fSYS_MHz			(fSYS_MHz),
	.fCK_MHz			(fCK_MHz),
	.REF_LATENCY		(2),
	.tIORT_u	        (tIORT_u),
	.DDIO_TYPE			(DDIO_TYPE),	
	.tPWRUP				(tPWRUP),
	.tRAS				(tRAS),
	.tRAS_MAX			(tRAS_MAX),
	.tRC				(tRC),
	.tRCD				(tRCD),
	.tREF				(tREF),
	.tRFC				(tRFC),
	.tRP				(tRP),
	.tWR				(tWR),
	.tMRD				(tMRD),
	.CL					(CL),
	.BL					(BL),
	.BA_WIDTH			(BA_WIDTH),
	.ROW_WIDTH			(ROW_WIDTH),
	.COL_WIDTH			(COL_WIDTH),
    .DATA_RATE          (DATA_RATE),
	.DQ_WIDTH			(DQ_WIDTH),
	.DQ_GROUP			(DQ_GROUP)
)
inst_sdram_controller
(
	.i_arst				(i_arst),
	.i_sysclk			(i_sysclk),
	.i_sdrclk			(i_sdrclk),
	.i_tACclk			(i_tACclk),
	.i_pll_locked		(i_pll_locked),
	
	.i_we				(i_we),
	.i_re				(i_re),
	.i_last				(i_last),
	.i_addr				(i_addr),
	.i_din				(i_din),
        .i_dm                           (i_dm),
	.o_dout				(o_dout),
	.o_sdr_state		(o_sdr_state),
	.o_sdr_init_done	(o_sdr_init_done),
	.o_wr_ack			(o_wr_ack),
	.o_rd_ack			(o_rd_ack),
	.o_ref_req			(o_ref_req),
	.o_rd_valid			(o_rd_valid),
	
	.o_sdr_CKE			(o_sdr_CKE),
	.o_sdr_n_CS			(o_sdr_n_CS),
	.o_sdr_n_RAS		(o_sdr_n_RAS),
	.o_sdr_n_CAS		(o_sdr_n_CAS),
	.o_sdr_n_WE			(o_sdr_n_WE),
	.o_sdr_BA			(o_sdr_BA),
	.o_sdr_ADDR			(o_sdr_ADDR),
	.o_sdr_DATA			(o_sdr_DATA),
	.o_sdr_DATA_oe		(o_sdr_DATA_oe),
	.i_sdr_DATA			(i_sdr_DATA),
	.o_sdr_DQM			(o_sdr_DQM),
	
	.o_dbg_dly_cnt_b	(o_dbg_dly_cnt_b),
	.o_dbg_tRCD_done	(o_dbg_tRCD_done),
	.o_dbg_tRTW_done	(o_dbg_tRTW_done),
	.o_dbg_ref_req		(o_dbg_ref_req),
	.o_dbg_wr_ack		(o_dbg_wr_ack),
	.o_dbg_rd_ack		(o_dbg_rd_ack),
	.o_dbg_n_CS			(o_dbg_n_CS),
	.o_dbg_n_RAS		(o_dbg_n_RAS),
	.o_dbg_n_CAS		(o_dbg_n_CAS),
	.o_dbg_n_WE			(o_dbg_n_WE),
	.o_dbg_BA			(o_dbg_BA),
	.o_dbg_ADDR			(o_dbg_ADDR),
	.o_dbg_DATA_out		(o_dbg_DATA_out),
	.o_dbg_DATA_in		(o_dbg_DATA_in)
);
end
endgenerate

endmodule


/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(sdram_controller).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      sdram controller top with native interface
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
//
// 1.0 Initial rev
// *******************************
////////////////////////////////////////////////////////////////

module `IP_MODULE_NAME(sdram_controller)
#(
	parameter	fSYS_MHz		= 100,
	parameter	fCK_MHz			= 100,
	parameter	REF_LATENCY		= 2,			// 2 for Native interface, 4 for AXI interface
	parameter	DDIO_TYPE		= "SOFT",		// SOFT, RTL
												// HARD, Interface Designer
	//sdram parameters
	parameter	tPWRUP			= 100,			// 100 us
	parameter	tRAS			= 44,			// 44 ns
	parameter	tRAS_MAX		= 120,			// 120 us
	parameter	tRC				= 66,		// 66 ns
	parameter	tRCD			= 20,			// 20 ns
	parameter	tREF			= 64,			// 64 ms
	parameter	tRFC			= 66,			// 66 ns
	parameter	tRP				= 20,		// 20 ns
	parameter	tWR				= 2,		// 1 CK+7.5 ns
	parameter	tMRD			= 2,			// 2 CK
	parameter	CL				= 3,		// 3 CK
	parameter	BL				= 1,
	parameter	BA_WIDTH		= 2,
	parameter	ROW_WIDTH		= 13,
	parameter	COL_WIDTH		= 10,
	parameter	DATA_RATE		= 1,	// 1, 2
    parameter   tIORT_u		    = 2,
	parameter	DQ_WIDTH		= 8,	// x4, x8
	parameter	DQ_GROUP		= 8
	//			x4	x8	x16	x32
	// DQ_WIDTH	4	8	8	8
	// DQ_GROUP	1	1	2	4
)
(
	input	i_arst,
	input	i_sysclk,
	input	i_sdrclk,	// x2 i_sysclk
	input	i_tACclk,	// x2 i_sysclk
	input	i_pll_locked,
	
	input	i_we,
	input	i_re,
	input	i_last,
	input	[			(BA_WIDTH+ROW_WIDTH+COL_WIDTH)	-1:0]	i_addr,
	input	[DATA_RATE	*DQ_GROUP		*DQ_WIDTH		-1:0]	i_din,
	input	[(DATA_RATE	*DQ_GROUP)                      -1:0]	i_dm,
	output	[DATA_RATE	*DQ_GROUP		*DQ_WIDTH		-1:0]	o_dout,
	output	[3:0]o_sdr_state,
	output	o_sdr_init_done,
	output	o_wr_ack,
	output	o_rd_ack,
	output	o_ref_req,
	output	o_rd_valid,
	
	output	[DATA_RATE							-1:0]	o_sdr_CKE,
	output	[DATA_RATE							-1:0]	o_sdr_n_CS,
	output	[DATA_RATE							-1:0]	o_sdr_n_RAS,
	output	[DATA_RATE							-1:0]	o_sdr_n_CAS,
	output	[DATA_RATE							-1:0]	o_sdr_n_WE,
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_sdr_BA,
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_sdr_ADDR,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA_oe,
	input	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	i_sdr_DATA,
	output	[DATA_RATE	*DQ_GROUP				-1:0]	o_sdr_DQM,
	
	// Debug port
	output	[5:0]o_dbg_dly_cnt_b,
	output	o_dbg_tRCD_done,
	output	o_dbg_tRTW_done,
	output	o_dbg_ref_req,
	output	o_dbg_wr_ack,
	output	o_dbg_rd_ack,
	output	[DATA_RATE							-1:0]	o_dbg_n_CS,
	output	[DATA_RATE							-1:0]	o_dbg_n_RAS,
	output	[DATA_RATE							-1:0]	o_dbg_n_CAS,
	output	[DATA_RATE							-1:0]	o_dbg_n_WE,
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_dbg_BA,
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_dbg_ADDR,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_dbg_DATA_out,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_dbg_DATA_in
);
`ifdef RTL_SIM
    localparam   tIORT		    = (DATA_RATE == 2 && CL == 2) ? 1 : 0;
`else
    localparam   tIORT		    = tIORT_u;
`endif
localparam  PARTIAL_FEATURES = (fCK_MHz == 166 && fSYS_MHz == 166) ? 1 : 0;  //partial features only applicable to 166Mhz fullrate
localparam  DLY_CNT_A_WIDTH	= (PARTIAL_FEATURES == 1) ? 4 : 6;
localparam  DLY_CNT_B_WIDTH	= (PARTIAL_FEATURES == 1) ? 4 : 6;
localparam  CHECK_ACT_BA	= (PARTIAL_FEATURES == 1) ? 1 : 4;
localparam	BA_MSB	= BA_WIDTH+	ROW_WIDTH+	COL_WIDTH-	1;
localparam	BA_LSB	= 			ROW_WIDTH+	COL_WIDTH;
localparam	ROW_MSB	= 			ROW_WIDTH+	COL_WIDTH-	1;
localparam	ROW_LSB	= 						COL_WIDTH;
localparam	COL_MSB	=						COL_WIDTH-	1;
localparam	COL_LSB	= 0;

localparam	CYC_A	= 0;
localparam	CYC_B	= 1;
localparam	CYC_C	= 2;
localparam	CYC_D	= 3;

wire	[DATA_RATE							-1:0]w_sdr_CKE;
wire	[DATA_RATE							-1:0]w_sdr_n_CS;
wire	[DATA_RATE							-1:0]w_sdr_n_RAS;
wire	[DATA_RATE							-1:0]w_sdr_n_CAS;
wire	[DATA_RATE							-1:0]w_sdr_n_WE;
wire	[DATA_RATE	*BA_WIDTH				-1:0]w_sdr_BA;
wire	[DATA_RATE	*ROW_WIDTH				-1:0]w_sdr_ADDR;
wire	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]w_sdr_DATA_out;
wire	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]w_sdr_DATA_oe;
wire	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]w_sdr_DATA_in;
wire	[DATA_RATE	*DQ_GROUP				-1:0]w_sdr_DQM;

`IP_MODULE_NAME(sdram_fsm)
#(
	.fSYS_MHz			(fSYS_MHz),
	.fCK_MHz			(fCK_MHz),
	.DLY_CNT_A_WIDTH	(DLY_CNT_A_WIDTH),
	.DLY_CNT_B_WIDTH	(DLY_CNT_B_WIDTH),
	.CHECK_ACT_BA		(CHECK_ACT_BA),
	.REF_LATENCY		(REF_LATENCY),
    .DATA_RATE	        (DATA_RATE),
	.tPWRUP				(tPWRUP),
	.tRAS				(tRAS),
	.tRAS_MAX			(tRAS_MAX),
	.tRC				(tRC),
	.tRCD				(tRCD),
	.tREF				(tREF),
	.tRFC				(tRFC),
	.tRP				(tRP),
	.tWR				(tWR),
	.tMRD				(tMRD),
	.CL					(CL),
	.BL					(BL),
	.tIORT				(tIORT),
	.DDIO_TYPE          (DDIO_TYPE),
	.BA_WIDTH			(BA_WIDTH),
	.ROW_WIDTH			(ROW_WIDTH),
	.COL_WIDTH			(COL_WIDTH),
	.DQ_WIDTH			(DQ_WIDTH),
	.DQ_GROUP			(DQ_GROUP)
)
inst_sdram_fsm
(
	.i_arst				(i_arst),
	.i_sysclk			(i_sysclk),
	.i_pll_locked		(i_pll_locked),
	
	.i_we				(i_we),
	.i_re				(i_re),
	.i_last				(i_last),
	.i_addr				(i_addr),
	.i_din				(i_din),
    .i_dm               (i_dm),
	.o_dout				(o_dout),
	.o_sdr_state		(o_sdr_state),
	.o_sdr_init_done	(o_sdr_init_done),
	.o_wr_ack			(o_wr_ack),
	.o_rd_ack			(o_rd_ack),
	.o_ref_req			(o_ref_req),
	.o_rd_valid			(o_rd_valid),
	
	.o_sdr_CKE			(w_sdr_CKE),
	.o_sdr_n_CS			(w_sdr_n_CS),
	.o_sdr_n_RAS		(w_sdr_n_RAS),
	.o_sdr_n_CAS		(w_sdr_n_CAS),
	.o_sdr_n_WE			(w_sdr_n_WE),
	.o_sdr_BA			(w_sdr_BA),
	.o_sdr_ADDR			(w_sdr_ADDR),
	.o_sdr_DATA			(w_sdr_DATA_out),
	.o_sdr_DATA_oe		(w_sdr_DATA_oe),
	.i_sdr_DATA			(w_sdr_DATA_in),
	.o_sdr_DQM			(w_sdr_DQM),
	
	.o_dbg_dly_cnt_b	(o_dbg_dly_cnt_b),
	.o_dbg_tRCD_done	(o_dbg_tRCD_done),
	.o_dbg_tRTW_done	(o_dbg_tRTW_done),
	.o_dbg_ref_req		(o_dbg_ref_req),
	.o_dbg_wr_ack		(o_dbg_wr_ack),
	.o_dbg_rd_ack		(o_dbg_rd_ack),
	.o_dbg_n_CS			(o_dbg_n_CS),
	.o_dbg_n_RAS		(o_dbg_n_RAS),
	.o_dbg_n_CAS		(o_dbg_n_CAS),
	.o_dbg_n_WE			(o_dbg_n_WE),
	.o_dbg_BA			(o_dbg_BA),
	.o_dbg_ADDR			(o_dbg_ADDR)
);

generate if (DDIO_TYPE == "SOFT" && DATA_RATE > 1) begin
    `IP_MODULE_NAME(sdram_io_block)
    #(
    	.DATA_RATE	(DATA_RATE),
    	.BA_WIDTH	(BA_WIDTH),
    	.ROW_WIDTH	(ROW_WIDTH),
    	.COL_WIDTH	(COL_WIDTH),
    	.DQ_WIDTH	(DQ_WIDTH),
    	.DQ_GROUP	(DQ_GROUP)
    )
    inst_sdram_io_block
    (
    	.i_arst				(i_arst),
    	.i_sysclk			(i_sysclk),
    	.i_sdrclk			(i_sdrclk),
    	.i_tACclk			(i_tACclk),
    	.i_pll_locked		(i_pll_locked),
    	
    	.i_sdr_CKE_core		(w_sdr_CKE),
    	.i_sdr_n_CS_core	(w_sdr_n_CS),
    	.i_sdr_n_RAS_core	(w_sdr_n_RAS),
    	.i_sdr_n_CAS_core	(w_sdr_n_CAS),
    	.i_sdr_n_WE_core	(w_sdr_n_WE),
    	.i_sdr_BA_core		(w_sdr_BA),
    	.i_sdr_ADDR_core	(w_sdr_ADDR),
    	.i_sdr_DATA_core	(w_sdr_DATA_out),
    	.i_sdr_DATA_oe_core	(w_sdr_DATA_oe),
    	.o_sdr_DATA_core	(w_sdr_DATA_in),
    	.i_sdr_DQM_core		(w_sdr_DQM),
    	
    	.o_sdr_CKE_pad		(o_sdr_CKE),
    	.o_sdr_n_CS_pad		(o_sdr_n_CS),
    	.o_sdr_n_RAS_pad	(o_sdr_n_RAS),
    	.o_sdr_n_CAS_pad	(o_sdr_n_CAS),
    	.o_sdr_n_WE_pad		(o_sdr_n_WE),
    	.o_sdr_BA_pad		(o_sdr_BA),
    	.o_sdr_ADDR_pad		(o_sdr_ADDR),
    	.o_sdr_DATA_pad		(o_sdr_DATA),
    	.o_sdr_DATA_oe_pad	(o_sdr_DATA_oe),
    	.i_sdr_DATA_pad		(i_sdr_DATA),
    	.o_sdr_DQM_pad		(o_sdr_DQM)
    );
end
else begin
    reg		[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]r_sdr_DATA_in_tACclk_1P;
    
    always@(posedge i_arst or posedge i_tACclk)
    begin
    	if (i_arst)
    		r_sdr_DATA_in_tACclk_1P	<= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}};
    	else
    		r_sdr_DATA_in_tACclk_1P	<= i_sdr_DATA;
    end
    
    assign	w_sdr_DATA_in	= r_sdr_DATA_in_tACclk_1P;
    assign	o_sdr_CKE		= w_sdr_CKE;
    assign	o_sdr_n_CS		= w_sdr_n_CS;
    assign	o_sdr_n_RAS		= w_sdr_n_RAS;
    assign	o_sdr_n_CAS		= w_sdr_n_CAS;
    assign	o_sdr_n_WE		= w_sdr_n_WE;
    assign	o_sdr_BA		= w_sdr_BA;
    assign	o_sdr_ADDR		= w_sdr_ADDR;
    assign	o_sdr_DATA		= w_sdr_DATA_out;
    assign	o_sdr_DATA_oe	= w_sdr_DATA_oe;
    assign	o_sdr_DQM		= w_sdr_DQM;   
end
endgenerate

assign	o_dbg_DATA_out	= w_sdr_DATA_out;
assign	o_dbg_DATA_in	= w_sdr_DATA_in;

endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(sdram_fsm).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      sdram controller state machine
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************

module `IP_MODULE_NAME(sdram_fsm)
#(
	parameter	fSYS_MHz		= 100,
	parameter	fCK_MHz			= 200,				// MHz
	parameter	DLY_CNT_A_WIDTH	= 6,
	parameter	DLY_CNT_B_WIDTH	= 6,
	parameter	CHECK_ACT_BA	= 4,
	parameter	REF_LATENCY		= 2,				// 
	
	parameter	tPWRUP			= 200,				// 100 us
	parameter	tRAS			= 44,				// 44 ns
	parameter	tRAS_MAX		= 120000,			// 120 us
	parameter	tRC				= 66,				// 66 ns
	parameter	tRCD			= 20,				// 20 ns
	parameter	tREF			= 64,				// 64 ms
	parameter	tRFC			= 66,				// 66 ns
	parameter	tRP				= 20,				// 20 ns
	parameter	tWR				= 2,				// 1 CK+7.5 ns
	parameter	tMRD			= 2,				// 2 CK
	parameter	CL				= 3,				// 3 CK
	parameter	BL				= 1,
	parameter	tIORT			= 2,
	parameter   DDIO_TYPE       = "SOFT",
	parameter	DATA_RATE		= 2,	
	parameter	BA_WIDTH		= 2,
	parameter	ROW_WIDTH		= 13,
	parameter	COL_WIDTH		= 10,
	parameter	DQ_WIDTH		= 8,	// x4, x8
	parameter	DQ_GROUP		= 4
	//			x4	x8	x16	x32
	// DQ_WIDTH	4	8	8	8
	// DQ_GROUP	1	1	2	4
)
(
	input	i_arst,
	input	i_sysclk,
	input	i_pll_locked,
	
	input	i_we,
	input	i_re,
	input	i_last,
	input	[			(BA_WIDTH+ROW_WIDTH+COL_WIDTH)	-1:0]	i_addr,
	input	[DATA_RATE	*DQ_GROUP		*DQ_WIDTH		-1:0]	i_din,
	input	[(DATA_RATE	*DQ_GROUP)                      -1:0]   i_dm,
	output	[DATA_RATE	*DQ_GROUP		*DQ_WIDTH		-1:0]	o_dout,
	output	[3:0]o_sdr_state,
	output	o_sdr_init_done,
	output	o_wr_ack,
	output	o_rd_ack,
	output	o_ref_req,
	output	o_rd_valid,
	
	output	[DATA_RATE							-1:0]	o_sdr_CKE,
	output	[DATA_RATE							-1:0]	o_sdr_n_CS,
	output	[DATA_RATE							-1:0]	o_sdr_n_RAS,
	output	[DATA_RATE							-1:0]	o_sdr_n_CAS,
	output	[DATA_RATE							-1:0]	o_sdr_n_WE,
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_sdr_BA,
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_sdr_ADDR,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA_oe,
	input	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	i_sdr_DATA,
	output	[DATA_RATE	*DQ_GROUP				-1:0]	o_sdr_DQM,
	
	output	[5:0]o_dbg_dly_cnt_b,
	output	o_dbg_tRCD_done,
	output	o_dbg_tRTW_done,
	output	o_dbg_ref_req,
	output	o_dbg_wr_ack,
	output	o_dbg_rd_ack,
	output	[DATA_RATE							-1:0]	o_dbg_n_CS,
	output	[DATA_RATE							-1:0]	o_dbg_n_RAS,
	output	[DATA_RATE							-1:0]	o_dbg_n_CAS,
	output	[DATA_RATE							-1:0]	o_dbg_n_WE,
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_dbg_BA,
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_dbg_ADDR
);

function integer log2;
	input	integer	val;
	integer	i;
	begin
		log2 = 0;
		for (i=0; 2**i<val; i=i+1)
			log2 = i+1;
	end
endfunction

localparam	DLY_CNT_C_WIDTH	= 16;  // counter for tPWRUP & tRAS_MAX
localparam	DLY_CNT_D_WIDTH	= 17;  // counter for tREF
	
//localparam	tCK		= (1000/fCK_MHz);
//+1 for parameter with minimum value, -1 for parameter wth maximum value
localparam	nPWRUP	= tPWRUP/(1000/fSYS_MHz) + 1;
localparam	nRAS	= tRAS/(1000/fSYS_MHz) + 1;
localparam	nRAS_MAX= tRAS_MAX/(1000/fSYS_MHz);
localparam	nRC		= tRC/(1000/fSYS_MHz) + 1;
localparam	nRCD	= tRCD/(1000/fSYS_MHz) + 1;
localparam	nREF	= (tREF/(2**ROW_WIDTH)/100)/(1000/fSYS_MHz);
localparam	nRFC	= tRFC/(1000/fSYS_MHz) + 1;
localparam	nRP		= tRP/(1000/fSYS_MHz) + 1;
localparam	nRTP	= CL-1'b1;
localparam	nRTW	= CL+tIORT;

//						 CRCW
//						  AA
//						 SSSE
localparam	c_NOP	= 4'b1111;
localparam	c_ACT	= 4'b0011;
localparam	c_RD	= 4'b0101;
localparam	c_WR	= 4'b0100;
localparam	c_BT	= 4'b0110;
localparam	c_PRE	= 4'b0010;
localparam	c_REF	= 4'b0001;
localparam	c_MRS	= 4'b0000;

localparam	BA_MSB	= BA_WIDTH+	ROW_WIDTH+	COL_WIDTH-	1;
localparam	BA_LSB	= 			ROW_WIDTH+	COL_WIDTH;
localparam	ROW_MSB	= 			ROW_WIDTH+	COL_WIDTH-	1;
localparam	ROW_LSB	= 						COL_WIDTH;
localparam	COL_MSB	=						COL_WIDTH-	1;
localparam	COL_LSB	= 0;

// M2-M0
localparam	BL1	= 3'b000;
localparam	BL2	= 3'b001;
localparam	BL4	= 3'b010;
localparam	BL8	= 3'b011;
localparam	BLP	= 3'b111;
// M3
localparam	SEQ	= 1'b0;
localparam	INT	= 1'b1;
// M6-M4
localparam	CL1	= 3'b001;
localparam	CL2	= 3'b010;
localparam	CL3	= 3'b011;
// M8-M7
localparam	STD	= 2'b00;
// M9
localparam	PBL	= 1'b0;
localparam	SLA	= 1'b1;

localparam	BURST_LENGTH	= (BL == 1)? BL1 :
								(BL == 2)? BL2 :
								  (BL == 4)? BL4 :	
								    (BL == 8)? BL8 : BL1;	
localparam	BURST_TYPE		= SEQ;
localparam	CAS_LATENCY		= CL;
localparam	OP_MODE			= PBL;

localparam	s_POWER_UP	= 4'b0000;
localparam	s_INIT_CKE	= 4'b0001;
localparam	s_INIT_PRE	= 4'b0010;
localparam	s_INIT_REF0	= 4'b0011;
localparam	s_INIT_REF1	= 4'b0100;
localparam	s_INIT_MRS	= 4'b0101;
localparam	s_IDLE		= 4'b0110;
localparam	s_ACT		= 4'b0111;
localparam	s_PRE		= 4'b1000;
localparam	s_REF		= 4'b1001;
reg		[3:0]r_sdr_state_1P;

localparam	PRE_ALL		= 1'b1;
localparam	PRE_SINGLE	= 1'b0;

localparam	CYC_A	= 0;
localparam	CYC_B	= 1;
localparam	CYC_C	= 2;
localparam	CYC_D	= 3;

`ifdef RTL_SIM
    localparam	RD_PIPE	= (DATA_RATE == 1 && DDIO_TYPE == "HARD") ? CL+tIORT+2 :	
	                    (DATA_RATE == 1 && DDIO_TYPE == "SOFT") ? CL+tIORT+2 : CL+tIORT+3;
`else
    localparam	RD_PIPE	= (DATA_RATE == 1 && DDIO_TYPE == "HARD") ? CL+tIORT+2 :	
	                    CL+tIORT+3;
`endif	                    
	                    
(* syn_preserve = "TRUE" *)reg		[DLY_CNT_A_WIDTH-1:0]r_dly_cnt_a_1P;
(* syn_preserve = "TRUE" *)reg		[DLY_CNT_B_WIDTH-1:0]r_dly_cnt_b_1P;
(* syn_preserve = "TRUE" *)reg		[DLY_CNT_C_WIDTH-1:0]r_dly_cnt_c_1P;
(* syn_preserve = "TRUE" *)reg		[DLY_CNT_D_WIDTH-1:0]r_dly_cnt_d_1P;
reg		r_sdr_init_done_1P;
reg		r_tRAS_done_1P;
reg		[REF_LATENCY-1:0]r_tRAS_MAX_done_1P;
reg		r_tRCD_done_1P;
reg		r_tRTP_done_1P;
reg		r_tRTW_done_1P;
reg		r_tWR_done_1P;
reg		r_tRC_done_1P;

reg		r_wr_ack_1P;
reg		[RD_PIPE:0]r_rd_ack_P;

reg		[ROW_WIDTH:0]r_act_row_1P[0:3];
reg		[BA_WIDTH+ROW_WIDTH-1:0]r_act_addr_1P;

reg		r_tRAS_MAX_1P;
reg		r_tRAS_MAX_2P;

reg     r_pre_allbank;

reg		r_oscclk_1P;
reg		[REF_LATENCY-1:0]r_ref_req_1P;
reg	    [6:0]	         r_sysclk_cnt_100_1P;
reg		[DATA_RATE							-1:0]	r_sdr_cke_1P;
reg		[DATA_RATE	*4						-1:0]	r_sdr_cmd_1P;
reg		[DATA_RATE	*BA_WIDTH				-1:0]	r_sdr_ba_1P;
reg		[DATA_RATE	*ROW_WIDTH				-1:0]	r_sdr_addr_1P;
reg		[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	r_sdr_dq_1P;
reg		[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	r_sdr_dqoe_1P;
reg		[DATA_RATE	*DQ_GROUP				-1:0]	r_sdr_dm_1P;

reg		[DATA_RATE	*4						-1:0]	r_sdr_cmd_2P;
reg		[DATA_RATE	*BA_WIDTH				-1:0]	r_sdr_ba_2P;
reg		[DATA_RATE	*ROW_WIDTH				-1:0]	r_sdr_addr_2P;
reg		[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	r_sdr_dqoe_2P;

reg		[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	r_sdr_dqin_1P;

integer	c, b;

wire	w_oscclk;
wire	w_tRAS_MAX;
wire	[BA_WIDTH-1:0]w_BA;
wire	[ROW_WIDTH-1:0]w_ROW;
wire	w_AFLAG;
wire	[ROW_WIDTH-1:0]w_AROW;
wire	w_pre_req;

assign	w_BA	= i_addr[BA_MSB:BA_LSB];
assign	w_ROW	= i_addr[ROW_MSB:ROW_LSB];
assign	w_AFLAG	= r_act_row_1P[w_BA][ROW_WIDTH];
assign	w_AROW	= r_act_row_1P[w_BA][ROW_WIDTH-1:0];

initial
begin
	$display("RD_PIPE = %d\n", RD_PIPE);
	$display("nPWRUP = %d\n", nPWRUP);
	$display("nRAS = %d\n", nRAS);
	$display("nRC = %d\n", nRC);
	$display("nREF = %d\n", nREF);
	$display("nRCD = %d\n", nRCD);
	$display("nRFC = %d\n", nRFC);
	$display("nRP = %d\n", nRP);
end

genvar k;
generate

    always@(posedge i_arst or posedge i_sysclk)
    begin
    	if (i_arst)
    		r_sysclk_cnt_100_1P	<= {7{1'b0}};
    	else
    	begin
    		if (r_sysclk_cnt_100_1P == 7'd98) begin
    		    r_sysclk_cnt_100_1P	<= {7{1'b0}};
    		end
    		else if (r_dly_cnt_d_1P == nREF-1) begin
    		    r_sysclk_cnt_100_1P	<= r_sysclk_cnt_100_1P+7'd1;
    		end
    		
    	end
    end
	
	if (CHECK_ACT_BA == 4)
		assign	w_pre_req	= (~w_AFLAG) || (w_AROW != w_ROW);
	else
		assign	w_pre_req	= r_act_addr_1P != {w_BA, w_ROW};
	
	for (k=0; k<REF_LATENCY-1; k=k+1)
	begin: REF_LATENCY_MAP
		always@(posedge i_arst or posedge i_sysclk)
		begin
			if (i_arst)
			begin
				r_ref_req_1P[k+1]	<= 1'b0;
			end
			else if (r_sdr_state_1P == s_REF && r_dly_cnt_a_1P == nRFC)
			begin
				r_ref_req_1P[k+1]	<= 1'b0;
			end
			else
			begin
				r_ref_req_1P[k+1]	<= r_ref_req_1P[k];
			end
		end
		
		always@(posedge i_arst or posedge i_sysclk)
		begin
			if (i_arst)
			begin
				r_tRAS_MAX_done_1P[k+1]	<= 1'b0;
			end
			else
			begin
				r_tRAS_MAX_done_1P[k+1]	<= r_tRAS_MAX_done_1P[k];
			end
		end
	end
endgenerate

always@(posedge i_arst or posedge i_sysclk)
begin
	if (i_arst)
	begin
		r_sdr_state_1P		<= s_POWER_UP;
		
		r_sdr_cke_1P		<= {DATA_RATE							{1'b0}};
		r_sdr_cmd_1P		<= {DATA_RATE							{c_NOP}};
		r_sdr_ba_1P			<= {DATA_RATE	*BA_WIDTH				{1'b0}};
		r_sdr_addr_1P		<= {DATA_RATE	*ROW_WIDTH				{1'b0}};
		r_sdr_dq_1P			<= {DATA_RATE	*DQ_GROUP	*DQ_WIDTH	{1'b0}};
		r_sdr_dqoe_1P		<= {DATA_RATE	*DQ_GROUP	*DQ_WIDTH	{1'b0}};
		r_sdr_dm_1P			<= {DATA_RATE	*DQ_GROUP				{1'b1}};
		r_act_row_1P[0]		<= {ROW_WIDTH+1{1'b0}};
		r_act_row_1P[1]		<= {ROW_WIDTH+1{1'b0}};
		r_act_row_1P[2]		<= {ROW_WIDTH+1{1'b0}};
		r_act_row_1P[3]		<= {ROW_WIDTH+1{1'b0}};
		r_act_addr_1P		<= {BA_WIDTH+ROW_WIDTH{1'b0}};
		
		r_sdr_cmd_2P		<= {DATA_RATE							{c_NOP}};
		r_sdr_ba_2P			<= {DATA_RATE	*BA_WIDTH				{1'b0}};
		r_sdr_addr_2P		<= {DATA_RATE	*ROW_WIDTH				{1'b0}};
		r_sdr_dqoe_2P		<= {DATA_RATE	*DQ_GROUP	*DQ_WIDTH	{1'b0}};
		
		r_dly_cnt_a_1P		<= {DLY_CNT_A_WIDTH{1'b0}};
		r_dly_cnt_b_1P		<= {DLY_CNT_B_WIDTH{1'b0}};
		r_dly_cnt_c_1P		<= {DLY_CNT_C_WIDTH{1'b0}};
		r_dly_cnt_d_1P      <= {DLY_CNT_D_WIDTH{1'b0}};
		r_sdr_init_done_1P	<= 1'b0;
		r_wr_ack_1P			<= 1'b0;
		r_rd_ack_P[0]		<= 1'b0;

		r_oscclk_1P			<= 1'b0;
		r_ref_req_1P[0]		<= 1'b0;
		r_tRAS_done_1P		<= 1'b0;
		r_tRAS_MAX_done_1P[0]	<= 1'b0;
		r_tRCD_done_1P		<= 1'b0;
		r_tRTP_done_1P		<= 1'b0;
		r_tRTW_done_1P		<= 1'b0;
		r_tWR_done_1P		<= 1'b0;
		r_tRC_done_1P		<= 1'b0;
		
		r_sdr_dqin_1P		<= {DQ_GROUP*DQ_WIDTH{1'b0}};
		r_pre_allbank       <= 1'b0;
	end
	else if (i_pll_locked)
	begin
		r_sdr_cmd_1P		<= {DATA_RATE							{c_NOP}};
		r_sdr_ba_1P			<= {DATA_RATE	*BA_WIDTH				{1'b0}};
		r_sdr_addr_1P		<= {DATA_RATE	*ROW_WIDTH				{1'b0}};
		r_sdr_dq_1P			<= {DATA_RATE	*DQ_GROUP	*DQ_WIDTH	{1'b0}};
		r_sdr_dqoe_1P		<= {DATA_RATE	*DQ_GROUP	*DQ_WIDTH	{1'b0}};
		r_sdr_dm_1P			<= {DATA_RATE	*DQ_GROUP				{1'b0}};
		r_sdr_cmd_2P		<= r_sdr_cmd_1P;
		r_sdr_ba_2P			<= r_sdr_ba_1P;
		r_sdr_addr_2P		<= r_sdr_addr_1P;
		r_sdr_dqoe_2P		<= r_sdr_dqoe_1P;
		
		r_wr_ack_1P			<= 1'b0;
		r_rd_ack_P[0]		<= 1'b0;
		
		r_sdr_dqin_1P		<= i_sdr_DATA;
		
		r_dly_cnt_a_1P		<= r_dly_cnt_a_1P+1'b1;
		r_dly_cnt_b_1P		<= r_dly_cnt_b_1P+1'b1;
		r_dly_cnt_c_1P		<= r_dly_cnt_c_1P+1'b1;
		
		if (r_dly_cnt_d_1P == nREF-1)
		    r_dly_cnt_d_1P      <= {DLY_CNT_D_WIDTH{1'b0}};
		else if (r_sdr_state_1P != s_POWER_UP)
		    r_dly_cnt_d_1P      <= r_dly_cnt_d_1P+1'b1;

		if (r_dly_cnt_b_1P == nRAS-1'b1)
			r_tRAS_done_1P	<= 1'b1;

		if (r_sysclk_cnt_100_1P == 7'd98)
			r_ref_req_1P[0]	<= 1'b1; 
			
		if (r_dly_cnt_b_1P == nRCD-1)
			r_tRCD_done_1P	<= 1'b1;
		
		if (r_dly_cnt_b_1P == nRTP-1)
			r_tRTP_done_1P	<= 1'b1;
		
		if (r_dly_cnt_b_1P == nRTW-1)
			r_tRTW_done_1P	<= 1'b1;
		
		if (r_dly_cnt_b_1P == tWR-1)
			r_tWR_done_1P	<= 1'b1;
		
		if (r_dly_cnt_b_1P == nRC-1)
			r_tRC_done_1P	<= 1'b1;
			
        if (r_dly_cnt_c_1P == nRAS_MAX && r_sdr_state_1P != s_POWER_UP) 
            r_tRAS_MAX_done_1P[0]  <= 1'b1;
		
		case (r_sdr_state_1P)
			s_POWER_UP:
			begin
				if (r_dly_cnt_c_1P == nPWRUP)  // count power up sequence
				begin
					r_sdr_state_1P	<= s_INIT_CKE;
					
					r_sdr_cke_1P	<= {DATA_RATE{1'b1}};
					r_dly_cnt_c_1P	<= {DLY_CNT_C_WIDTH{1'b0}};
				end
			end
			
			s_INIT_CKE:
			begin
				r_sdr_state_1P			<= s_INIT_PRE;
				
				r_sdr_cmd_1P[CYC_A+:4]	<= c_PRE;
				r_sdr_addr_1P[CYC_A+10]	<= PRE_ALL;
				
				r_dly_cnt_a_1P			<= {DLY_CNT_A_WIDTH{1'b0}};
			end
			
			s_INIT_PRE:
			begin
				if (r_dly_cnt_a_1P == nRP)
				begin
					r_sdr_state_1P			<= s_INIT_REF0;
					
					r_sdr_cmd_1P[CYC_A+:4]	<= c_REF;
					
					r_dly_cnt_a_1P			<= {DLY_CNT_A_WIDTH{1'b0}};
				end
			end
			
			s_INIT_REF0:
			begin
				if (r_dly_cnt_a_1P == nRFC)
				begin
					r_sdr_state_1P			<= s_INIT_REF1;
					
					r_sdr_cmd_1P[CYC_A+:4]	<= c_REF;
					
					r_dly_cnt_a_1P			<= {DLY_CNT_A_WIDTH{1'b0}};
				end
			end
			
			s_INIT_REF1:
			begin
				if (r_dly_cnt_a_1P == nRFC)
				begin
					r_sdr_state_1P					<= s_INIT_MRS;
					
					r_sdr_cmd_1P[CYC_A+:4]			<= c_MRS;
					r_sdr_addr_1P[CYC_A+:ROW_WIDTH]	<= {{ROW_WIDTH-10{1'b0}},
														OP_MODE, CAS_LATENCY,
														BURST_TYPE, BURST_LENGTH};
					
					r_dly_cnt_a_1P					<= {DLY_CNT_A_WIDTH{1'b0}};
				end
			end
			
			s_INIT_MRS:
			begin
				if (r_dly_cnt_a_1P == tMRD-1'b1)
				begin
					r_sdr_state_1P		<= s_IDLE;
					r_sdr_dm_1P			<= {DATA_RATE*DQ_GROUP{1'b0}};
					r_sdr_init_done_1P	<= 1'b1;
					r_tRCD_done_1P		<= 1'b0;
					r_tRTP_done_1P		<= 1'b0;
					r_tWR_done_1P		<= 1'b0;
					r_tRC_done_1P		<= 1'b0;
				end
			end
			
			s_IDLE:
			begin
				if (r_ref_req_1P[REF_LATENCY-1])
				begin
					if (CHECK_ACT_BA == 4 && (
						r_act_row_1P[0][ROW_WIDTH] || r_act_row_1P[1][ROW_WIDTH] ||
						r_act_row_1P[2][ROW_WIDTH] || r_act_row_1P[3][ROW_WIDTH ]))
					begin
						r_sdr_state_1P				<= s_PRE;
						
						r_sdr_cmd_1P[CYC_A+:4]		<= c_PRE;
						r_sdr_addr_1P[CYC_A+10]		<= PRE_ALL;
						r_act_row_1P[0][ROW_WIDTH]	<= 1'b0;
						r_act_row_1P[1][ROW_WIDTH]	<= 1'b0;
						r_act_row_1P[2][ROW_WIDTH]	<= 1'b0;
						r_act_row_1P[3][ROW_WIDTH]	<= 1'b0;
						
						r_dly_cnt_a_1P				<= {DLY_CNT_A_WIDTH{1'b0}};
					end
					else
					begin
						r_sdr_state_1P			<= s_REF;
						
						r_sdr_cmd_1P[CYC_A+:4]	<= c_REF;
						
						r_dly_cnt_a_1P			<= {DLY_CNT_A_WIDTH{1'b0}};
					end
				end
				else if (i_we || i_re)
				begin
					r_sdr_state_1P		<= s_ACT;
					
					r_sdr_cmd_1P[CYC_A+:4]			<= c_ACT;
					r_sdr_ba_1P[CYC_A+:BA_WIDTH]	<= i_addr[BA_MSB:BA_LSB];
					r_sdr_addr_1P[CYC_A+:ROW_WIDTH]	<= i_addr[ROW_MSB:ROW_LSB];
					
					if (CHECK_ACT_BA == 4)
						r_act_row_1P[w_BA]	<= {1'b1, w_ROW};
					r_act_addr_1P		<= {w_BA, w_ROW};

					r_dly_cnt_b_1P		  <= {DLY_CNT_B_WIDTH{1'b0}};
					r_dly_cnt_c_1P        <= {DLY_CNT_C_WIDTH{1'b0}};
					r_tRAS_done_1P		  <= 1'b0;
					r_tRCD_done_1P		  <= 1'b0;
					r_tRC_done_1P		  <= 1'b0;
					r_tRAS_MAX_done_1P[0] <= 1'b0;
				end
			end
			
			s_ACT:
			begin
				if (r_ref_req_1P[REF_LATENCY-1] || r_tRAS_MAX_done_1P[REF_LATENCY-1])
				begin
					if (r_tRAS_done_1P && r_tWR_done_1P && r_tRTP_done_1P)
					begin
						r_sdr_state_1P				<= s_PRE;
						
						r_sdr_cmd_1P[CYC_A+:4]		<= c_PRE;
						r_sdr_addr_1P[CYC_A+10]		<= PRE_ALL;
						r_sdr_ba_2P                 <= r_sdr_ba_2P;
						r_sdr_addr_2P               <= r_sdr_addr_2P;  // do not assign r_sdr_addr_1P to r_sdr_addr_2P because r_sdr_addr_1P was zero in previous clock
						r_pre_allbank               <= 1'b1;
						if (CHECK_ACT_BA == 4)
						begin
							r_act_row_1P[0][ROW_WIDTH]	<= 1'b0;
							r_act_row_1P[1][ROW_WIDTH]	<= 1'b0;
							r_act_row_1P[2][ROW_WIDTH]	<= 1'b0;
							r_act_row_1P[3][ROW_WIDTH]	<= 1'b0;
						end
						
						r_dly_cnt_a_1P		<= {DLY_CNT_A_WIDTH{1'b0}};
					end
				end
				else if (i_we || i_re)
				begin
					if (w_pre_req)
					begin
						if (r_tRC_done_1P && r_tRAS_done_1P &&
							r_tWR_done_1P && r_tRTP_done_1P)
						begin
							r_sdr_state_1P					<= s_PRE;
							
							r_sdr_cmd_1P[CYC_A+:4]			<= c_PRE;
							r_sdr_ba_1P[CYC_A+:BA_WIDTH]	<= i_addr[BA_MSB:BA_LSB];
							r_sdr_addr_1P[CYC_A+10]			<= PRE_SINGLE;
							if (CHECK_ACT_BA == 4)
								r_act_row_1P[w_BA][ROW_WIDTH]	<= 1'b0;
							
							r_dly_cnt_a_1P					<= {DLY_CNT_A_WIDTH{1'b0}};
						end
					end
					else if (r_tRCD_done_1P)
					begin
						if (i_we && r_tRTW_done_1P)
						begin
							if (DATA_RATE == 1)
							begin
								r_sdr_cmd_1P[CYC_A+:4]			<= c_WR;
								r_sdr_ba_2P[CYC_A+:BA_WIDTH]	<= i_addr[BA_MSB:BA_LSB];
								r_sdr_addr_2P[CYC_A+:COL_WIDTH]	<= i_addr[COL_MSB:COL_LSB];
							end
							else
							begin
								for (c=0; c<DATA_RATE; c=c+1)
								begin
									r_sdr_cmd_1P[c*4+:4]				<= c_WR;
									r_sdr_ba_2P[c*BA_WIDTH+:BA_WIDTH]	<= i_addr[BA_MSB:BA_LSB];
									r_sdr_addr_2P[c*ROW_WIDTH+log2(DATA_RATE)+:COL_WIDTH-log2(DATA_RATE)]	<= i_addr[COL_MSB:COL_LSB+log2(DATA_RATE)];
									for (b=0; b<log2(DATA_RATE); b=b+1)
									begin
										r_sdr_addr_2P[c*ROW_WIDTH+b]	<= (c & 32'hFFFFFFFF) >> b;
									end
								end
							end
							
							r_sdr_dq_1P		<= i_din;
							r_sdr_dm_1P     <= i_dm;
							r_sdr_dqoe_1P	<= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b1}};
							
							r_dly_cnt_b_1P	<= {DLY_CNT_B_WIDTH{1'b0}};
							r_tWR_done_1P	<= 1'b0;
							
							r_wr_ack_1P		<= ~r_ref_req_1P[0];
							
							if (REF_LATENCY > 2) begin
							    if (r_ref_req_1P[1] || r_tRAS_MAX_done_1P[1] || (i_last & r_wr_ack_1P))   //
							    begin
							    		r_sdr_cmd_1P			<= {DATA_RATE{c_NOP}};
							    		r_sdr_dqoe_1P			<= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}};
							    		r_wr_ack_1P				<= 1'b0;
							    end
							end
							else begin
							    if (r_ref_req_1P[REF_LATENCY-2] || r_tRAS_MAX_done_1P[REF_LATENCY-2] || (i_last & r_wr_ack_1P))
							    begin
							    		r_sdr_cmd_1P			<= {DATA_RATE{c_NOP}};
							    		r_sdr_dqoe_1P			<= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}};
							    		r_wr_ack_1P				<= 1'b0;
							    end
							end
						
						end
						else if (~i_we && i_re)
						begin
							if (DATA_RATE == 1)
							begin
								r_sdr_cmd_1P	<= c_RD;
								r_sdr_ba_2P		<= i_addr[BA_MSB:BA_LSB];
								r_sdr_addr_2P	<= i_addr[COL_MSB:COL_LSB];
							end
							else
							begin
								for (c=0; c<DATA_RATE; c=c+1)
								begin
									r_sdr_cmd_1P[c*4+:4]				<= c_RD;
									r_sdr_ba_2P[c*BA_WIDTH+:BA_WIDTH]	<= i_addr[BA_MSB:BA_LSB];
									r_sdr_addr_2P[c*ROW_WIDTH+log2(DATA_RATE)+:COL_WIDTH-log2(DATA_RATE)]	<= i_addr[COL_MSB:COL_LSB+log2(DATA_RATE)];
									for (b=0; b<log2(DATA_RATE); b=b+1)
									begin
										r_sdr_addr_2P[c*ROW_WIDTH+b]	<= (c & 32'hFFFFFFFF) >> b;
									end
								end
							end
							
							r_dly_cnt_b_1P	<= {DLY_CNT_B_WIDTH{1'b0}};
							r_tRTW_done_1P	<= 1'b0;
							r_tRC_done_1P	<= 1'b0;
							
							r_rd_ack_P[0]	<= ~r_ref_req_1P[0];
							
							if (REF_LATENCY > 2) begin
							    if (r_ref_req_1P[1] || r_tRAS_MAX_done_1P[1] || (i_last & r_rd_ack_P[0]))
							    begin
							    	if (r_rd_ack_P[0])
							    	begin
							    		r_sdr_cmd_1P			<= {DATA_RATE{c_NOP}};
							    		r_sdr_dqoe_1P			<= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}};
							    		r_rd_ack_P[0]			<= 1'b0;
							    	end
							    end
							end
							else begin
							    if (r_ref_req_1P[REF_LATENCY-2] || r_tRAS_MAX_done_1P[REF_LATENCY-2] || (i_last & r_rd_ack_P[0]))
							    begin
							    	if (r_rd_ack_P[0])
							    	begin
							    		r_sdr_cmd_1P			<= {DATA_RATE{c_NOP}};
							    		r_sdr_dqoe_1P			<= {DATA_RATE*DQ_GROUP*DQ_WIDTH{1'b0}};
							    		r_rd_ack_P[0]			<= 1'b0;
							    	end
							    end
							end
						end
					end
				end
			end
			
			s_PRE:
			begin
				if (r_dly_cnt_a_1P == nRP-1'b1)
				begin
					if (r_ref_req_1P[REF_LATENCY-1])
					begin
						if (r_pre_allbank)  // check if the previous PRE is ALL_BANK or SINGLE_BANK
						begin                   
						    r_sdr_state_1P			<= s_REF;
						    r_sdr_cmd_1P[CYC_A+:4]	<= c_REF;
						    r_pre_allbank           <= 1'b0;
						    r_dly_cnt_a_1P			<= {DLY_CNT_A_WIDTH{1'b0}};
						end
						else 
						begin // if the previous PRE is SINGLE_BANK, issue PRE to ALL_BANK before trigger AUTO-refresh
						    r_sdr_state_1P			<= s_PRE;
						    r_sdr_cmd_1P[CYC_A+:4]	<= c_PRE;
						    r_sdr_addr_1P[CYC_A+10] <= PRE_ALL;
						    r_pre_allbank           <= 1'b1;
						    if (CHECK_ACT_BA == 4)
						    begin
						    	r_act_row_1P[0][ROW_WIDTH]	<= 1'b0;
						    	r_act_row_1P[1][ROW_WIDTH]	<= 1'b0;
						    	r_act_row_1P[2][ROW_WIDTH]	<= 1'b0;
						    	r_act_row_1P[3][ROW_WIDTH]	<= 1'b0;
						    end
						    r_dly_cnt_a_1P			<= {DLY_CNT_A_WIDTH{1'b0}};
						end
					end
					else
					begin
						r_sdr_state_1P	<= s_IDLE;
					end
				end
			end
			
			s_REF:
			begin
				if (r_dly_cnt_a_1P == nRFC)
				begin
					r_sdr_state_1P	<= s_IDLE;
					r_ref_req_1P[0]	<= 1'b0;
		            r_dly_cnt_d_1P  <= {DLY_CNT_D_WIDTH{1'b0}};
				end
			end
		endcase
	end
end

assign	o_sdr_state		= r_sdr_state_1P;
assign	o_sdr_init_done	= r_sdr_init_done_1P;
assign	o_wr_ack		= r_wr_ack_1P;
genvar i;
generate
	for (i=1; i<=RD_PIPE; i=i+1)
	begin: readback
		always@(posedge i_arst or posedge i_sysclk)
		begin
			if (i_arst)
				r_rd_ack_P[i]	<= 1'b0;
			else
				r_rd_ack_P[i]	<= r_rd_ack_P[i-1];
		end
	end
endgenerate
assign	o_rd_ack		= r_rd_ack_P[0];
assign	o_ref_req		= r_ref_req_1P[0];
assign	o_rd_valid		= r_rd_ack_P[RD_PIPE];
assign	o_dout			= r_sdr_dqin_1P;

assign	o_sdr_CKE		= r_sdr_cke_1P;
genvar j;
generate
	for (j=0; j<DATA_RATE; j=j+1)
	begin: cycle_mapping
		assign	o_sdr_n_CS[j]	= r_sdr_cmd_2P[j*4+3];
		assign	o_sdr_n_RAS[j]	= r_sdr_cmd_2P[j*4+2];
		assign	o_sdr_n_CAS[j]	= r_sdr_cmd_2P[j*4+1];
		assign	o_sdr_n_WE[j]	= r_sdr_cmd_2P[j*4+0];
		
		assign	o_dbg_n_CS[j]	= r_sdr_cmd_2P[j*4+3];
		assign	o_dbg_n_RAS[j]	= r_sdr_cmd_2P[j*4+2];
		assign	o_dbg_n_CAS[j]	= r_sdr_cmd_2P[j*4+1];
		assign	o_dbg_n_WE[j]	= r_sdr_cmd_2P[j*4+0];
	end
endgenerate
assign	o_sdr_BA		= r_sdr_ba_2P;
assign	o_sdr_ADDR		= r_sdr_addr_2P;
assign	o_sdr_DATA		= r_sdr_dq_1P;
assign	o_sdr_DQM		= r_sdr_dm_1P;
assign	o_sdr_DATA_oe	= r_sdr_dqoe_2P;

assign	o_dbg_dly_cnt_b	= (DLY_CNT_B_WIDTH == 4) ? {2'b00, r_dly_cnt_b_1P} : r_dly_cnt_b_1P;
assign	o_dbg_tRCD_done	= r_tRCD_done_1P;
assign	o_dbg_tRTW_done	= r_tRTW_done_1P;
assign	o_dbg_ref_req	= r_ref_req_1P[REF_LATENCY-2];
assign	o_dbg_wr_ack	= r_wr_ack_1P;
assign	o_dbg_rd_ack	= r_rd_ack_P[0];

assign	o_dbg_BA		= r_sdr_ba_2P;
assign	o_dbg_ADDR		= r_sdr_addr_2P;

endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(sdram_io_block).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      sdram controller I/O alignment
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************
/////////////////////////////////////////////////////////////////////////////

module `IP_MODULE_NAME(sdram_io_block)
#(
	parameter	DATA_RATE		= 2,		// Do not over write
	parameter	BA_WIDTH		= 2,
	parameter	ROW_WIDTH		= 13,
	parameter	COL_WIDTH		= 10,
	parameter	DQ_WIDTH		= 8,	// x4, x8
	parameter	DQ_GROUP		= 2
)
(
	input	i_arst,
	input	i_sysclk,
	input	i_sdrclk,
	input	i_tACclk,
	input	i_pll_locked,
	
	input	[DATA_RATE							-1:0]	i_sdr_CKE_core,
	input	[DATA_RATE							-1:0]	i_sdr_n_CS_core,
	input	[DATA_RATE							-1:0]	i_sdr_n_RAS_core,
	input	[DATA_RATE							-1:0]	i_sdr_n_CAS_core,
	input	[DATA_RATE							-1:0]	i_sdr_n_WE_core,
	input	[DATA_RATE	*BA_WIDTH				-1:0]	i_sdr_BA_core,
	input	[DATA_RATE	*ROW_WIDTH				-1:0]	i_sdr_ADDR_core,
	input	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	i_sdr_DATA_core,
	input	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	i_sdr_DATA_oe_core,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA_core,
	input	[DATA_RATE	*DQ_GROUP				-1:0]	i_sdr_DQM_core,
	
	output	[DATA_RATE							-1:0]	o_sdr_CKE_pad,
	output	[DATA_RATE							-1:0]	o_sdr_n_CS_pad,
	output	[DATA_RATE							-1:0]	o_sdr_n_RAS_pad,
	output	[DATA_RATE							-1:0]	o_sdr_n_CAS_pad,
	output	[DATA_RATE							-1:0]	o_sdr_n_WE_pad,
	output	[DATA_RATE	*BA_WIDTH				-1:0]	o_sdr_BA_pad,
	output	[DATA_RATE	*ROW_WIDTH				-1:0]	o_sdr_ADDR_pad,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA_pad,
	output	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	o_sdr_DATA_oe_pad,
	input	[DATA_RATE	*DQ_GROUP	*DQ_WIDTH	-1:0]	i_sdr_DATA_pad,
	output	[DATA_RATE	*DQ_GROUP				-1:0]	o_sdr_DQM_pad
);

localparam	BA_MSB	= BA_WIDTH+	ROW_WIDTH+	COL_WIDTH-	1;
localparam	BA_LSB	= 			ROW_WIDTH+	COL_WIDTH;
localparam	ROW_MSB	= 			ROW_WIDTH+	COL_WIDTH-	1;
localparam	ROW_LSB	= 						COL_WIDTH;
localparam	COL_MSB	=						COL_WIDTH-	1;
localparam	COL_LSB	= 0;

localparam	CYC_A	= 0;
localparam	CYC_B	= 1;
localparam	CYC_C	= 2;
localparam	CYC_D	= 3;

wire	[DATA_RATE*DQ_GROUP*DQ_WIDTH-1:0]w_sdr_DATA_core;
reg		[DQ_GROUP*DQ_WIDTH-1:0]r_sdr_DATA_core_1P;
reg		r_pll_locked_1P;

genvar rate;

initial
begin
	$display("Data Rate = %d\n", DATA_RATE);
`ifdef RTL_SIM
	$display("RTL_SIM\n");
`endif
end

always@(posedge i_arst or posedge i_sysclk)
begin
	if (i_arst)
	begin
		r_pll_locked_1P	<= 1'b0;
	end
	else
	begin
		r_pll_locked_1P	<= i_pll_locked;
	end
end

    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(1),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_CKE
    (
    	.arst(i_arst),
    	.d0(i_sdr_CKE_core[CYC_A]),
    	.d1(i_sdr_CKE_core[CYC_B]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_CKE_pad[CYC_A])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(1),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_CS
    (
    	.arst(i_arst),
    	.d0(i_sdr_n_CS_core[CYC_A]),
    	.d1(i_sdr_n_CS_core[CYC_B]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_n_CS_pad[CYC_A])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(1),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_RAS
    (
    	.arst(i_arst),
    	.d0(i_sdr_n_RAS_core[CYC_A]),
    	.d1(i_sdr_n_RAS_core[CYC_B]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_n_RAS_pad[CYC_A])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(1),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_CAS
    (
    	.arst(i_arst),
    	.d0(i_sdr_n_CAS_core[CYC_A]),
    	.d1(i_sdr_n_CAS_core[CYC_B]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_n_CAS_pad[CYC_A])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(1),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_WE
    (
    	.arst(i_arst),
    	.d0(i_sdr_n_WE_core[CYC_A]),
    	.d1(i_sdr_n_WE_core[CYC_B]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_n_WE_pad[CYC_A])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(BA_WIDTH),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_BA
    (
    	.arst(i_arst),
    	.d0(i_sdr_BA_core[CYC_A*BA_WIDTH+:BA_WIDTH]),
    	.d1(i_sdr_BA_core[CYC_B*BA_WIDTH+:BA_WIDTH]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_BA_pad[BA_WIDTH-1:0])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(ROW_WIDTH),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_ADDR
    (
    	.arst(i_arst),
    	.d0(i_sdr_ADDR_core[CYC_A*ROW_WIDTH+:ROW_WIDTH]), 
    	.d1(i_sdr_ADDR_core[CYC_B*ROW_WIDTH+:ROW_WIDTH]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_ADDR_pad[ROW_WIDTH-1:0])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(DQ_GROUP*DQ_WIDTH),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_DQ_OUT
    (
    	.arst(i_arst),
    	.d0(i_sdr_DATA_core[CYC_A*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH]),   
    	.d1(i_sdr_DATA_core[CYC_B*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_DATA_pad[DQ_GROUP*DQ_WIDTH-1:0])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(DQ_GROUP*DQ_WIDTH),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_DQ_oe
    (
    	.arst(i_arst),
    	.d0(i_sdr_DATA_oe_core[CYC_A*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH]),
    	.d1(i_sdr_DATA_oe_core[CYC_B*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_DATA_oe_pad[DQ_GROUP*DQ_WIDTH-1:0])
    );
    
    `IP_MODULE_NAME(sync_ddio_group_in)
    #(
    	.DW		(DQ_GROUP*DQ_WIDTH),
    	.SYNC	("RISING")   
    )
    inst_DQ_IN
    (
    	.arst	(i_arst),
    	.c_x1	(i_sysclk),
    	.c_x2	(i_tACclk),
    	.d		(i_sdr_DATA_pad[DQ_GROUP*DQ_WIDTH-1:0]),
`ifdef RTL_SIM
        .q0		(o_sdr_DATA_core[CYC_A*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH]),	// simulation
        .q1		(o_sdr_DATA_core[CYC_B*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH])	// simulation
`else
        .q0		(w_sdr_DATA_core[CYC_A*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH]),
        .q1		(w_sdr_DATA_core[CYC_B*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH])
`endif
    );
    
    `IP_MODULE_NAME(sync_ddio_group_out)
    #(
    	.DW(DQ_GROUP),
    	.INIT(1'b0),
    	.SYNC("RISING")
    )
    inst_DQM
    (
    	.arst(i_arst),
    	.d0(i_sdr_DQM_core[CYC_A*DQ_GROUP+:DQ_GROUP]),
    	.d1(i_sdr_DQM_core[CYC_B*DQ_GROUP+:DQ_GROUP]),
    	.c_x1(i_sysclk),
    	.c_x2(i_sdrclk),
    	.lock(r_pll_locked_1P),
    	.c(),
    	.q(o_sdr_DQM_pad[DQ_GROUP-1:0])
    );
			
`ifndef RTL_SIM
    // on board
    always@(posedge i_arst or posedge i_sysclk)
    begin
    	if (i_arst)
    		r_sdr_DATA_core_1P	<= {DQ_GROUP*DQ_WIDTH{1'b0}};
    	else
    		r_sdr_DATA_core_1P	<= w_sdr_DATA_core[CYC_B*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH];
    end
    assign	o_sdr_DATA_core	= {	w_sdr_DATA_core[CYC_A*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH],
    							r_sdr_DATA_core_1P};
`endif
	generate
	    for (rate=1; rate<DATA_RATE; rate=rate+1)
	    begin: cycle_mapping
	    	assign	o_sdr_CKE_pad[rate]		= 1'b0;
	    	assign	o_sdr_n_CS_pad[rate]	= 1'b0;
	    	assign	o_sdr_n_RAS_pad[rate]	= 1'b0;
	    	assign	o_sdr_n_CAS_pad[rate]	= 1'b0;
	    	assign	o_sdr_n_WE_pad[rate]	= 1'b0;
	    	assign	o_sdr_BA_pad[rate*BA_WIDTH+:BA_WIDTH]		= {BA_WIDTH{1'b0}};
	    	assign	o_sdr_ADDR_pad[rate*ROW_WIDTH+:ROW_WIDTH]	= {ROW_WIDTH{1'b0}};
	    	assign	o_sdr_DATA_pad[rate*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH]		= {DQ_GROUP*DQ_WIDTH{1'b0}};
	    	assign	o_sdr_DATA_oe_pad[rate*DQ_GROUP*DQ_WIDTH+:DQ_GROUP*DQ_WIDTH]	= {DQ_GROUP*DQ_WIDTH{1'b0}};
	    	assign	o_sdr_DQM_pad[rate*DQ_GROUP+:DQ_GROUP]		= {DQ_GROUP{1'b0}};
	    end
    endgenerate
endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
/////////////////////////////////////////////////////////////////////////////

	`define CLK_200    	

	`define SYS_CLK_100     	

	`define tPWRUP     	      200000

	`define tRAS       	          44

	`define tRAS_MAX   	      120000

	`define tRC        	          66

	`define tRCD       	          20

	`define tREF       	    64000000

	`define tRFC       	          66

	`define tRP        	          20

	`define tWR        	           2

	`define tMRD       	           2

	`define ba_width   	           2

	`define row_width  	          13

	`define col_width  	          10

	`define dq_width   	           8

	`define dq_group   	           2

	`define fsys_mhz   	         100

	`define fck_mhz    	         200

	`define cl         	           3

	`define bl         	           1

	`define ddio_type  	 "SOFT"
	
	`define tIORT                  2
	
	`define SDRAM_MODE		"AXI4" //"Native"





/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   simple_dual_port_ram.v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      simple dual port ram macro
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************

module `IP_MODULE_NAME(sdram_simple_dual_port_ram)
#(
	parameter DATA_WIDTH	= 8,
	parameter ADDR_WIDTH	= 9,
	parameter OUTPUT_REG	= "TRUE",
	parameter RAM_INIT_FILE	= ""
)
(
	input [(DATA_WIDTH-1):0] wdata,
	input [(ADDR_WIDTH-1):0] waddr, raddr,
	input we, wclk, re, rclk,
	output [(DATA_WIDTH-1):0] rdata
);

	localparam MEMORY_DEPTH = 2**ADDR_WIDTH;
	localparam MAX_DATA = (1<<ADDR_WIDTH)-1;
	
	reg [DATA_WIDTH-1:0] ram[MEMORY_DEPTH-1:0];
	reg [DATA_WIDTH-1:0] r_rdata_1P;
	reg [DATA_WIDTH-1:0] r_rdata_2P;
	
	reg [DATA_WIDTH-1:0] i;
	initial
	begin
	// By default the Efinix memory will initialize to 0
		if (RAM_INIT_FILE != "")
		begin
			$readmemh(RAM_INIT_FILE, ram);
		end
		else
		begin
			for (i=0;i<=MEMORY_DEPTH-1;i=i+1)
                ram[i] = i[DATA_WIDTH-1:0];
		end
	end
	
	always @ (posedge wclk)
		if (we)
		ram[waddr] <= wdata;
	
	always @ (posedge rclk)
	begin
		if (re)
			r_rdata_1P <= ram[raddr];
		r_rdata_2P <= r_rdata_1P;
	end
	
	generate
		if (OUTPUT_REG == "TRUE")
			assign	rdata = r_rdata_2P;
		else
			assign	rdata = r_rdata_1P;
	endgenerate

endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(sync_ddio_group_in).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      soft DDIO input
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************
/////////////////////////////////////////////////////////////////////////////

module `IP_MODULE_NAME(sync_ddio_group_in)
#(
	parameter	DW		= 1,
	parameter	SYNC	= "RISING"
)
(
	input	arst,
	input	c_x1,
	input	c_x2,
	input	[DW-1:0]d,
	output	[DW-1:0]q0,
	output	[DW-1:0]q1
);

reg		[DW-1:0]r_d_x2_1P;
reg		[DW-1:0]r_d_x2_2P;

reg		[DW-1:0]r_d0_x1_2P;
reg		[DW-1:0]r_d1_x1_2P;

always@(posedge arst or posedge c_x2)
begin
	if (arst)
	begin
		r_d_x2_1P	<= {DW{1'b0}};
		r_d_x2_2P	<= {DW{1'b0}};
	end
	else
	begin
		r_d_x2_1P	<= d;
		r_d_x2_2P	<= r_d_x2_1P;
	end
end

    always@(posedge arst or posedge c_x1)
    begin
    	if (arst)
    	begin
    		r_d0_x1_2P	<= {DW{1'b0}};
    		r_d1_x1_2P	<= {DW{1'b0}};
    	end
    	else
    	begin
    		if (SYNC == "FALLING")
    		begin
    			r_d0_x1_2P	<= r_d_x2_1P;
    			r_d1_x1_2P	<= r_d_x2_2P;
    		end
    		else
    		begin
    			r_d0_x1_2P	<= r_d_x2_2P;
    			r_d1_x1_2P	<= r_d_x2_1P;
    		end
    	end
    end

assign	q0	= r_d0_x1_2P;
assign	q1	= r_d1_x1_2P;

endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//           _____       
//          / _______    Copyright (C) 2013-2020 Efinix Inc. All rights reserved.
//         / /       \   
//        / /  ..    /   `IP_MODULE_NAME(sync_ddio_group_out).v
//       / / .'     /    
//    __/ /.'      /     Description:
//   __   \       /      soft DDIO output
//  /_/ /\ \_____/ /     
// ____/  \_______/      
//
// *******************************
// Revisions:
// 1.0 Initial rev
//
// *******************************
/////////////////////////////////////////////////////////////////////////////

module `IP_MODULE_NAME(sync_ddio_group_out)
#(
	parameter	DW		= 1,
	parameter	INIT	= 1'b0,
	parameter	SYNC	= "RISING"
)
(
	input	arst,
	input	[DW-1:0]d0,
	input	[DW-1:0]d1,
	input	c_x1,
	input	c_x2,
	input	lock,
	output	c,
	output	[DW-1:0]q
);

reg		[DW-1:0]r_d0_x1_1P;
reg		[DW-1:0]r_d1_x1_1P;

reg		r_c_x2_1P;
reg		r_s_x2_1P;
reg		[DW-1:0]r_d_x2_2P;

wire	w_c_rst;

generate
	if (SYNC == "FALLING")
		assign	w_c_rst	= 1'b1;
	else
		assign	w_c_rst	= 1'b0;
endgenerate

always@(posedge arst or posedge c_x1)
begin
	if (arst)
	begin
		r_d0_x1_1P	<= {DW{INIT}};
		r_d1_x1_1P	<= {DW{INIT}};
	end
	else if (lock)
	begin
		r_d0_x1_1P	<= d0;
		r_d1_x1_1P	<= d1;
	end
end

always@(posedge arst or posedge c_x2)
begin
	if (arst)
	begin
		r_c_x2_1P	<= w_c_rst;
		r_s_x2_1P	<= 1'b0;
		r_d_x2_2P	<= {DW{INIT}};
	end
	else if (lock)
	begin
		r_c_x2_1P	<= ~r_c_x2_1P;
		r_s_x2_1P	<= ~r_s_x2_1P;
		if (r_s_x2_1P)
			r_d_x2_2P	<= r_d1_x1_1P;
		else
			r_d_x2_2P	<= r_d0_x1_1P;
	end
end

assign	c	= r_c_x2_1P;
assign	q	= r_d_x2_2P;

endmodule

//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2019 Efinix Inc. All rights reserved.
//
// This   document  contains  proprietary information  which   is
// protected by  copyright. All rights  are reserved.  This notice
// refers to original work by Efinix, Inc. which may be derivitive
// of other work distributed under license of the authors.  In the
// case of derivative work, nothing in this notice overrides the
// original author's license agreement.  Where applicable, the 
// original license agreement is included in it's original 
// unmodified form immediately below this header.
//
// WARRANTY DISCLAIMER.  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND 
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH 
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, 
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR 
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED 
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.
//
// LIMITATION OF LIABILITY.  
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY 
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT 
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY 
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, 
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY 
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF 
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR 
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN 
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER 
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR 
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT 
//     APPLY TO LICENSEE.
//
/////////////////////////////////////////////////////////////////////////////
`undef IP_UUID
`undef IP_NAME_CONCAT
`undef IP_MODULE_NAME
