
module IS42VM16400K_Cntlr(
  input	clk,									//74.25Mhz
  input clkx2,
  input clkx2deg45,
  input	rst_n,
  
  input [15:0]			D_Sensor_1,
  input [15:0]			D_Sensor_2,
  output reg [31:0]		D_Sensor_Out,
  input 				WR_EN,
  input 				RD_EN,
  input 				Prech_EN,
  input					Active_EN,
  input [11:0]			Row_Addr,
  output reg 			init_done,
    
  inout [15:0]	 		sdr_DQ,        // sdr data
  output reg [11:0]		sdr_A,         // sdr address
  output reg [1:0] 		sdr_BA,        // sdr bank address
  output 				sdr_CKE,       // sdr clock enable
  output 				sdr_CSn,       // sdr chip select
  output reg			sdr_RASn,      // sdr row address
  output reg			sdr_CASn,      // sdr column select
  output reg			sdr_WEn,       // sdr write enable
  output [1:0]  		sdr_DQM,	   // sdr write data mask
  output 				sdr_CLK	       //148.5Mhz
); 
parameter init_precharge = 7425;		 //initialization: precharge after      100us                 >=7425 clks
parameter init_autoref   = 7430;		 //                auto refresh after   100us+22.5ns          >=7425+4=7429 clks
parameter init_autoref2	 = 7445;		 //                auto refresh 2 after 100us+22.5ns+80ns     >=7425+4+13=7442 clks
parameter init_mode		 = 7460;		 //				   mode register prog.  100us+22.5ns+80ns+80ns>=7425+4+13+13=7455 clks
parameter init_active	 = 7470;		 //				   activate banks 0 and 1
parameter precharge      = 1;
parameter autoref        = 2;
parameter mode           = 3;
parameter write          = 4;
parameter read           = 5;
parameter active         = 6;
reg [12:0] clk_cnt;
wire[12:0] n_clk_cnt;
wire [2:0] cmd;
reg [31:0] q_sdr_dq;
reg [15:0] q_sdr_dq_2;
wire [31:0] n_sdr_dq;
reg [15:0] q_sdr_dq_in;
reg RASn, CASn, WEn, q_sdr_RASn, q_sdr_CASn, q_sdr_WEn;
reg q_WR_EN, q_WR_EN_1, q_RD_EN, q_RD_EN_1, q_RD_EN_2, q_Prech_EN, q_Active_EN, q_Active_EN_1, q_Active_EN_2;
reg [15:0] q_D_Sensor_1, q_D_Sensor_1_1;
reg [15:0] q_D_Sensor_2, q_D_Sensor_2_1;
reg [11:0] A, q_sdr_A;
reg [1:0] BA, q_sdr_BA;
reg [15:0] sdr_DQ_out;
wire [15:0] DQ; 
reg  [15:0] q_DQ;
reg q_img_switch;

always@(posedge clk or negedge rst_n) begin
   if(!rst_n) begin
   		clk_cnt			<= 	0;
		init_done		<=  0;
		D_Sensor_Out	<=	0;
   		q_RD_EN				<=	0;
		q_WR_EN				<=  0;
		q_RD_EN_1			<=	0;
		q_RD_EN_2			<=	0;
		q_WR_EN_1			<= 0;
		q_Prech_EN			<= 0;
		q_Active_EN			<= 0;
		q_Active_EN_1			<= 0;
		q_Active_EN_2			<= 0;
   		q_sdr_dq_2		<= 0;
   		q_D_Sensor_1		<= 0;
   		q_D_Sensor_2		<= 0;
   		q_D_Sensor_1_1		<= 0;
   		q_D_Sensor_2_1		<= 0;
   		q_sdr_RASn 			<= 1;
		q_sdr_CASn 			<= 1;
		q_sdr_WEn  			<= 1;
		q_sdr_BA			<= 0;
		q_sdr_A				<= 0;
		q_img_switch		<= 0;
   end
   else begin
	    clk_cnt			<= n_clk_cnt;
		D_Sensor_Out	<= {q_sdr_dq/*[31:16],q_sdr_dq_2*/};
		q_RD_EN				<= RD_EN;
		q_WR_EN				<= WR_EN;
		q_RD_EN_1			<= q_RD_EN;
		q_RD_EN_2			<= q_RD_EN_1;
		q_WR_EN_1			<= q_WR_EN;
		q_Prech_EN			<= Prech_EN;  
		q_Active_EN			<= Active_EN;
		q_Active_EN_1			<= q_Active_EN;
		q_Active_EN_2			<= q_Active_EN_1;
		q_sdr_dq_2			<= q_sdr_dq[15:0];
		q_D_Sensor_1		<= D_Sensor_1;
		q_D_Sensor_2		<= D_Sensor_2;
		q_D_Sensor_1_1		<= q_D_Sensor_1;
		q_D_Sensor_2_1		<= q_D_Sensor_2;		
		q_sdr_RASn 			<= RASn;
		q_sdr_CASn 			<= CASn;
		q_sdr_WEn  			<= WEn;	
		q_sdr_BA			<= BA;
		q_sdr_A				<= A;
		q_img_switch		<= (Row_Addr<1800) ? 1'b0:1'b1;
		if (clk_cnt<=7500)
		   init_done		<= init_done;
        else 
	 	   init_done		<= 1;
   end
end
always@(posedge clkx2 or negedge rst_n) begin
   if(!rst_n) begin		   
		//q_sdr_dq_in		<=  0;
		//q_sdr_dq		<=	0;
		sdr_RASn 			<= 1;
		sdr_CASn 			<= 1;
		sdr_WEn  			<= 1; 
		sdr_BA				<= 0;
		sdr_A				<= 0;
		sdr_DQ_out			<= 0;
		q_DQ				<= 0;
		//q_sdr_dq_in		<=  0;
		//q_sdr_dq		<=	0;
	end
else begin 
		//q_sdr_dq_in			<= sdr_DQ;
		//q_sdr_dq			<= n_sdr_dq; 
		sdr_RASn 			<= (!q_sdr_RASn) ? (q_sdr_RASn || ~clk) : q_sdr_RASn;
		sdr_CASn 			<= (!q_sdr_RASn) ? (q_sdr_CASn || ~clk) : q_sdr_CASn;
		sdr_WEn  			<= (!q_sdr_RASn) ? (q_sdr_WEn  || ~clk) : q_sdr_WEn;  
		sdr_BA[0]			<=	(/*WR_EN||*/q_WR_EN||q_WR_EN_1)				? ~clk :
								(/*RD_EN||*/q_RD_EN||q_RD_EN_1/*||q_RD_EN_2*/)				? q_img_switch :
								q_sdr_BA; //~clk & q_WR_EN_1;
		sdr_A[11:1]			<= q_sdr_A[11:1];
		sdr_A[0]			<= (q_RD_EN||q_RD_EN_1) ? ~clk	:	q_sdr_A[0];
		q_DQ				<= DQ;
		sdr_DQ_out			<= DQ;
		//q_sdr_dq_in			<= sdr_DQ;
		//q_sdr_dq			<= n_sdr_dq; 
   end
end
always@(posedge clkx2deg45 or negedge rst_n) begin
   if(!rst_n) begin		   
		q_sdr_dq_in		<=  0;
		q_sdr_dq		<=	0;
	end
else begin 
		q_sdr_dq_in			<= sdr_DQ;
		q_sdr_dq			<= n_sdr_dq; 
   end
end

assign n_sdr_dq[15:0]	  = clk		?	sdr_DQ/*q_sdr_dq_in*/ : q_sdr_dq[15:0];
assign n_sdr_dq[31:16]    = ~clk	?	sdr_DQ/*q_sdr_dq_in*/ : q_sdr_dq[31:16];

assign n_clk_cnt =	(~init_done || q_WR_EN || q_RD_EN)		? clk_cnt + 1 : 0;
assign DQ = clk ? q_D_Sensor_1_1 : q_D_Sensor_2_1; 
assign sdr_DQ = (q_WR_EN||q_WR_EN_1) ? sdr_DQ_out : 16'bz;

assign cmd = (clk_cnt==init_precharge) ? precharge	    :							
             (clk_cnt==init_autoref)   ? autoref		:
			 (clk_cnt==init_autoref2)  ? autoref		:
			 (clk_cnt==init_mode)      ? mode			: 
			 //(clk_cnt==init_active)    ? active			: 
			 (init_done & q_WR_EN)	   ? write			:
			 (init_done & q_RD_EN)	   ? read			: 
			 (init_done & q_Prech_EN)  ? precharge		:
			 (init_done & (q_Active_EN||q_Active_EN_2))   ? active			: 0;

always@(*) begin
			BA   <= 2'b00;
			A    <= 12'hFFF;	
			RASn <= 1'b1;				//NOP
			CASn <= 1'b1;
			WEn  <= 1'b1;
	case (cmd) 
		precharge:
		begin
			RASn <= 1'b0;
			CASn <= 1'b1;
			WEn  <= 1'b0;
			A    <= 12'h400;
		end
		autoref:
		begin
			RASn <= 1'b0;
			CASn <= 1'b0;
			WEn  <= 1'b1;
		end
		mode:
		begin
			RASn <= 1'b0;
			CASn <= 1'b0;
			WEn  <= 1'b0;
			BA	 <= 2'b00;
			A    <= 12'h030;		//cas latency = 3, burst = 1			
		end
		write:
		begin
			RASn <= 1'b1;
			CASn <= 1'b0;
			WEn  <= 1'b0;
			BA	 <= 2'b00;
			A    <= {2'b00,clk_cnt[9:0]}; //write with NO precharge					
		end
		read:
		begin
			RASn <= 1'b1;
			CASn <= 1'b0;
			WEn  <= 1'b1;
			BA	 <= (Row_Addr<1800) ? 2'b00 : 2'b01;  //720/2*(5 rows_per_line)=1800					
			A    <= {2'b00,clk_cnt[8:0],1'b0};	//read with no precharge	
		end
		active:
		begin
			RASn <= 1'b0;
			CASn <= 1'b1;
			WEn  <= 1'b1;
			BA	 <= {1'b0, q_Active_EN_2};
			A    <= (Row_Addr<1800) ? Row_Addr : (Row_Addr-1800);
		end
	endcase	
end

assign sdr_CSn = 1'b0;
assign sdr_CKE = 1'b1;
assign sdr_DQM = 2'b00;
assign sdr_clk = clkx2;
assign sdr_CLK = clkx2deg45;
	
endmodule