///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------
//-- Title      : APB Master to Configure MDDR
//-------------------------------------------------------------------------------
//-- File       : MDDR_Config.v
//-- Author     : Corporate Applications Engineering
//-- Company    : Microsemi Corporation
//-- Device     : SmartFusion2
//-- Standard   : Verilog
//-------------------------------------------------------------------------------
//-- Description: This code implementes the APB master logic to configure the MDDR   
//--              to access DDR3 memory on SmartFusion2 DEV KIT at 320 MHz.
//-------------------------------------------------------------------------------
//-- Copyright (c) 2013   Microsemi Corporation
//--                      All rights reserved.
//-------------------------------------------------------------------------------
//-- Revisions  : V1.0
//-------------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////////////////////////// 

module MDDR_Config( 
	input CLK,
	input RESETn,
	
	input PREADY,
	input PSLVERR,
	input [15:0] PRDATA,

	output reg [15:0] PWDATA,
	output wire [15:2] PADDR,
	output reg PSEL,
	output reg PENABLE,
	output reg PWRITE,

	output reg DRAM_Ready
      );


reg [2:0] apb_fsm_current_state;
parameter [2:0] Idle = 3'b000, Write_0 = 3'b001, Write_1 = 3'b010, Write_2 = 3'b011, Read_0 = 3'b100, Read_1 = 3'b101, Write_3 = 3'b110;

reg [11:0] count_delay;

reg [15:2] PADDR_int;
reg [6:0] i;
wire [15:0] DDRC_Reg[129:0];

assign	DDRC_Reg[0] = 16'h0000;//#define MDDR_DDRC_DYN_SOFT_RESET_CR 0x4
assign	DDRC_Reg[1] = 16'h0000;//#define MDDR_DDRC_RESERVED0 0x0
assign	DDRC_Reg[2] = 16'h15BE;//#define MDDR_DDRC_DYN_REFRESH_1_CR 0x15BE
assign	DDRC_Reg[3] = 16'h028F;//#define MDDR_DDRC_DYN_REFRESH_2_CR 0x28F
assign	DDRC_Reg[4] = 16'h0002;//#define MDDR_DDRC_DYN_POWERDOWN_CR 0x2
assign	DDRC_Reg[5] = 16'h0000;//#define MDDR_DDRC_DYN_DEBUG_CR 0x0
assign	DDRC_Reg[6] = 16'h0101;//#define MDDR_DDRC_MODE_CR 0x101
assign	DDRC_Reg[7] = 16'h0999;//#define MDDR_DDRC_ADDR_MAP_BANK_CR 0x0999
assign	DDRC_Reg[8] = 16'h0000;//#define MDDR_DDRC_ECC_DATA_MASK_CR 0x0
assign	DDRC_Reg[9] = 16'h3333;//#define MDDR_DDRC_ADDR_MAP_COL_1_CR 0x3333
assign	DDRC_Reg[10] = 16'hFFFF;//#define MDDR_DDRC_ADDR_MAP_COL_2_CR 0xFFFF
assign	DDRC_Reg[11] = 16'h8888;//#define MDDR_DDRC_ADDR_MAP_ROW_1_CR 0x8888
assign	DDRC_Reg[12] = 16'h0888;//#define MDDR_DDRC_ADDR_MAP_ROW_2_CR 0x0888
assign	DDRC_Reg[13] = 16'h0001;//#define MDDR_DDRC_INIT_1_CR 0x1
assign	DDRC_Reg[14] = 16'h100;//#define MDDR_DDRC_CKE_RSTN_CYCLES_CR1 0x4242
assign	DDRC_Reg[15] = 16'h0008;//#define MDDR_DDRC_CKE_RSTN_CYCLES_CR2 0x8
assign	DDRC_Reg[16] = 16'h0310;//#define MDDR_DDRC_INIT_MR_CR 0x310
assign	DDRC_Reg[17] = 16'h0000;//#define MDDR_DDRC_INIT_EMR_CR 0x00
assign	DDRC_Reg[18] = 16'h0000;//#define MDDR_DDRC_INIT_EMR2_CR 0x0
assign	DDRC_Reg[19] = 16'h0000;//#define MDDR_DDRC_INIT_EMR3_CR 0x0
assign	DDRC_Reg[20] = 16'h044A;//#define MDDR_DDRC_DRAM_BANK_TIMING_PARAM_CR 0x44A
assign	DDRC_Reg[21] = 16'h0085;//#define MDDR_DDRC_DRAM_RD_WR_LATENCY_CR 0x85
assign	DDRC_Reg[22] = 16'h0235;//#define MDDR_DDRC_DRAM_RD_WR_PRE_CR 0x235
assign	DDRC_Reg[23] = 16'h0064;//#define MDDR_DDRC_DRAM_MR_TIMING_PARAM_CR 0x64
assign	DDRC_Reg[24] = 16'h02CC;//#define MDDR_DDRC_DRAM_RAS_TIMING_CR 0x2CC
assign	DDRC_Reg[25] = 16'h0178;//#define MDDR_DDRC_DRAM_RD_WR_TRNARND_TIME_CR 0x178
assign	DDRC_Reg[26] = 16'h0033;//#define MDDR_DDRC_DRAM_T_PD_CR 0x33
assign	DDRC_Reg[27] = 16'h1535;//#define MDDR_DDRC_DRAM_BANK_ACT_TIMING_CR 0x1535
assign	DDRC_Reg[28] = 16'h0010;//#define MDDR_DDRC_ODT_PARAM_1_CR 0x10
assign	DDRC_Reg[29] = 16'h0000;//#define MDDR_DDRC_ODT_PARAM_2_CR 0x0
assign	DDRC_Reg[30] = 16'h3300;//#define MDDR_DDRC_DEBUG_CR 0x3300
assign	DDRC_Reg[31] = 16'h0000;//#define MDDR_DDRC_MODE_REG_RD_WR_CR 0x0
assign	DDRC_Reg[32] = 16'h0000;//#define MDDR_DDRC_MODE_REG_DATA_CR 0x0
assign	DDRC_Reg[33] = 16'h0406;//#define MDDR_DDRC_PWR_SAVE_1_CR 0x406
assign	DDRC_Reg[34] = 16'h0000;//#define MDDR_DDRC_PWR_SAVE_2_CR 0x0
assign	DDRC_Reg[35] = 16'h0200;//#define MDDR_DDRC_ZQ_LONG_TIME_CR 0x200
assign	DDRC_Reg[36] = 16'h0040;//#define MDDR_DDRC_ZQ_SHORT_TIME_CR 0x40
assign	DDRC_Reg[37] = 16'h0012;//#define MDDR_DDRC_ZQ_SHORT_INT_REFRESH_MARGIN_CR1 0x12
assign	DDRC_Reg[38] = 16'h0002;//#define MDDR_DDRC_ZQ_SHORT_INT_REFRESH_MARGIN_CR2 0x2
assign	DDRC_Reg[39] = 16'h4000;//#define MDDR_DDRC_PERF_PARAM_1_CR 0x4000
assign	DDRC_Reg[40] = 16'h80F8;//#define MDDR_DDRC_HPR_QUEUE_PARAM_CR1 0x80F8
assign	DDRC_Reg[41] = 16'h0007;//#define MDDR_DDRC_HPR_QUEUE_PARAM_CR2 0x07
assign	DDRC_Reg[42] = 16'h80F8;//#define MDDR_DDRC_LPR_QUEUE_PARAM_CR1 0x80F8
assign	DDRC_Reg[43] = 16'h0007;//#define MDDR_DDRC_LPR_QUEUE_PARAM_CR2 0x07
assign	DDRC_Reg[44] = 16'h0200;//#define MDDR_DDRC_WR_QUEUE_PARAM_CR 0x200
assign	DDRC_Reg[45] = 16'h0000;//#define MDDR_DDRC_PERF_PARAM_2_CR 0x00
assign	DDRC_Reg[46] = 16'h0000;//#define MDDR_DDRC_PERF_PARAM_3_CR 0x0
assign	DDRC_Reg[47] = 16'h0004;//#define MDDR_DDRC_DFI_RDDATA_EN_CR 0x4
assign	DDRC_Reg[48] = 16'h0003;//#define MDDR_DDRC_DFI_MIN_CTRLUPD_TIMING_CR 0x3
assign	DDRC_Reg[49] = 16'h0040;//#define MDDR_DDRC_DFI_MAX_CTRLUPD_TIMING_CR 0x40
assign	DDRC_Reg[50] = 16'h0000;//#define MDDR_DDRC_DFI_WR_LVL_CONTROL_CR1 0x0
assign	DDRC_Reg[51] = 16'h0000;//#define MDDR_DDRC_DFI_WR_LVL_CONTROL_CR2 0x0
assign	DDRC_Reg[52] = 16'h0000;//#define MDDR_DDRC_DFI_RD_LVL_CONTROL_CR1 0x0
assign	DDRC_Reg[53] = 16'h0000;//#define MDDR_DDRC_DFI_RD_LVL_CONTROL_CR2 0x0
assign	DDRC_Reg[54] = 16'h0309;//#define MDDR_DDRC_DFI_CTRLUPD_TIME_INTERVAL_CR 0x309
assign	DDRC_Reg[55] = 16'h0001;//#define MDDR_DDRC_DYN_SOFT_RESET_ALIAS_CR 0x1
assign	DDRC_Reg[56] = 16'h0000;//#define MDDR_DDRC_AXI_FABRIC_PRI_ID_CR 0x0


assign	DDRC_Reg[57] = 16'h0080;//#define MDDR_PHY_CTRL_SLAVE_RATIO_CR 0x80
assign	DDRC_Reg[58] = 16'h0000;//#define MDDR_PHY_CTRL_SLAVE_FORCE_CR 0x0
assign	DDRC_Reg[59] = 16'h0000;//#define MDDR_PHY_CTRL_SLAVE_DELAY_CR 0x0
assign	DDRC_Reg[60] = 16'h000F;//#define MDDR_PHY_DATA_SLICE_IN_USE_CR 0xF
assign	DDRC_Reg[61] = 16'h0000;//#define MDDR_PHY_LVL_NUM_OF_DQ0_CR 0x0
assign	DDRC_Reg[62] = 16'h0000;//#define MDDR_PHY_DQ_OFFSET_CR1 0x0
assign	DDRC_Reg[63] = 16'h0000;//#define MDDR_PHY_DQ_OFFSET_CR2 0x0
assign	DDRC_Reg[64] = 16'h0000;//#define MDDR_PHY_DQ_OFFSET_CR3 0x0
assign	DDRC_Reg[65] = 16'h0000;//#define MDDR_PHY_DIS_CALIB_RST_CR 0x0
assign	DDRC_Reg[66] = 16'h000B;//#define MDDR_PHY_DLL_LOCK_DIFF_CR 0xB
assign	DDRC_Reg[67] = 16'h0000;//#define MDDR_PHY_FIFO_WE_IN_DELAY_CR1 0x0
assign	DDRC_Reg[68] = 16'h0000;//#define MDDR_PHY_FIFO_WE_IN_DELAY_CR2 0x0
assign	DDRC_Reg[69] = 16'h0000;//#define MDDR_PHY_FIFO_WE_IN_DELAY_CR3 0x0
assign	DDRC_Reg[70] = 16'h0000;//#define MDDR_PHY_FIFO_WE_IN_FORCE_CR 0x0
assign	DDRC_Reg[71] = 16'h0080;//#define MDDR_PHY_FIFO_WE_SLAVE_RATIO_CR1 0x80
assign	DDRC_Reg[72] = 16'h2004;//#define MDDR_PHY_FIFO_WE_SLAVE_RATIO_CR2 0x2004
assign	DDRC_Reg[73] = 16'h0100;//#define MDDR_PHY_FIFO_WE_SLAVE_RATIO_CR3 0x100
assign	DDRC_Reg[74] = 16'h0008;//#define MDDR_PHY_FIFO_WE_SLAVE_RATIO_CR4 0x8
assign	DDRC_Reg[75] = 16'h0000;//#define MDDR_PHY_GATELVL_INIT_MODE_CR 0x0
assign	DDRC_Reg[76] = 16'h0000;//#define MDDR_PHY_GATELVL_INIT_RATIO_CR1 0x0
assign	DDRC_Reg[77] = 16'h0000;//#define MDDR_PHY_GATELVL_INIT_RATIO_CR2 0x0
assign	DDRC_Reg[78] = 16'h0000;//#define MDDR_PHY_GATELVL_INIT_RATIO_CR3 0x0
assign	DDRC_Reg[79] = 16'h0000;//#define MDDR_PHY_GATELVL_INIT_RATIO_CR4 0x0
assign	DDRC_Reg[80] = 16'h0001;//#define MDDR_PHY_LOCAL_ODT_CR 0x1
assign	DDRC_Reg[81] = 16'h0000;//#define MDDR_PHY_INVERT_CLKOUT_CR 0x0
assign	DDRC_Reg[82] = 16'h0000;//#define MDDR_PHY_RD_DQS_SLAVE_DELAY_CR1 0x0
assign	DDRC_Reg[83] = 16'h0000;//#define MDDR_PHY_RD_DQS_SLAVE_DELAY_CR2 0x0
assign	DDRC_Reg[84] = 16'h0000;//#define MDDR_PHY_RD_DQS_SLAVE_DELAY_CR3 0x0
assign	DDRC_Reg[85] = 16'h0000;//#define MDDR_PHY_RD_DQS_SLAVE_FORCE_CR 0x0
assign	DDRC_Reg[86] = 16'h4050;//#define MDDR_PHY_RD_DQS_SLAVE_RATIO_CR1 0x4050
assign	DDRC_Reg[87] = 16'h0501;//#define MDDR_PHY_RD_DQS_SLAVE_RATIO_CR2 0x501
assign	DDRC_Reg[88] = 16'h5014;//#define MDDR_PHY_RD_DQS_SLAVE_RATIO_CR3 0x5014
assign	DDRC_Reg[89] = 16'h0000;//#define MDDR_PHY_RD_DQS_SLAVE_RATIO_CR4 0x0
assign	DDRC_Reg[90] = 16'h0000;//#define MDDR_PHY_WR_DQS_SLAVE_DELAY_CR1 0x0
assign	DDRC_Reg[91] = 16'h0000;//#define MDDR_PHY_WR_DQS_SLAVE_DELAY_CR2 0x0
assign	DDRC_Reg[92] = 16'h0000;//#define MDDR_PHY_WR_DQS_SLAVE_DELAY_CR3 0x0
assign	DDRC_Reg[93] = 16'h0000;//#define MDDR_PHY_WR_DQS_SLAVE_FORCE_CR 0x0
assign	DDRC_Reg[94] = 16'h0000;//#define MDDR_PHY_WR_DQS_SLAVE_RATIO_CR1 0x0
assign	DDRC_Reg[95] = 16'h0000;//#define MDDR_PHY_WR_DQS_SLAVE_RATIO_CR2 0x0
assign	DDRC_Reg[96] = 16'h0000;//#define MDDR_PHY_WR_DQS_SLAVE_RATIO_CR3 0x0
assign	DDRC_Reg[97] = 16'h0000;//#define MDDR_PHY_WR_DQS_SLAVE_RATIO_CR4 0x0
assign	DDRC_Reg[98] = 16'h0000;//#define MDDR_PHY_WR_DATA_SLAVE_DELAY_CR1 0x0
assign	DDRC_Reg[99] = 16'h0000;//#define MDDR_PHY_WR_DATA_SLAVE_DELAY_CR2 0x0
assign	DDRC_Reg[100] = 16'h0000;//#define MDDR_PHY_WR_DATA_SLAVE_DELAY_CR3 0x0
assign	DDRC_Reg[101] = 16'h0000;//#define MDDR_PHY_WR_DATA_SLAVE_FORCE_CR 0x0
assign	DDRC_Reg[102] = 16'h0050;//#define MDDR_PHY_WR_DATA_SLAVE_RATIO_CR1 0x50
assign	DDRC_Reg[103] = 16'h0501;//#define MDDR_PHY_WR_DATA_SLAVE_RATIO_CR2 0x501
assign	DDRC_Reg[104] = 16'h5010;//#define MDDR_PHY_WR_DATA_SLAVE_RATIO_CR3 0x5010
assign	DDRC_Reg[105] = 16'h0000;//#define MDDR_PHY_WR_DATA_SLAVE_RATIO_CR4 0x0
assign	DDRC_Reg[106] = 16'h0000;//#define MDDR_PHY_WRLVL_INIT_MODE_CR 0x0
assign	DDRC_Reg[107] = 16'h0000;//#define MDDR_PHY_WRLVL_INIT_RATIO_CR1 0x0
assign	DDRC_Reg[108] = 16'h0000;//#define MDDR_PHY_WRLVL_INIT_RATIO_CR2 0x0
assign	DDRC_Reg[109] = 16'h0000;//#define MDDR_PHY_WRLVL_INIT_RATIO_CR3 0x0
assign	DDRC_Reg[110] = 16'h0000;//#define MDDR_PHY_WRLVL_INIT_RATIO_CR4 0x0
assign	DDRC_Reg[111] = 16'h0043;//#define MDDR_PHY_WR_RD_RL_CR 0x43
assign	DDRC_Reg[112] = 16'h0000;//#define MDDR_PHY_RDC_FIFO_RST_ERR_CNT_CLR_CR 0x0
assign	DDRC_Reg[113] = 16'h0003;//#define MDDR_PHY_RDC_WE_TO_RE_DELAY_CR 0x3
assign	DDRC_Reg[114] = 16'h0001;//#define MDDR_PHY_USE_FIXED_RE_CR 0x1
assign	DDRC_Reg[115] = 16'h0001;//#define MDDR_PHY_USE_RANK0_DELAYS_CR 0x1
assign	DDRC_Reg[116] = 16'h0000;//#define MDDR_PHY_USE_LVL_TRNG_LEVEL_CR 0x0
assign	DDRC_Reg[117] = 16'h0000;//#define MDDR_PHY_DYN_CONFIG_CR 0x0
assign	DDRC_Reg[118] = 16'h0000;//#define MDDR_PHY_RD_WR_GATE_LVL_CR 0x0
assign	DDRC_Reg[119] = 16'h0001;//#define MDDR_PHY_DYN_RESET_CR 0x1

assign PADDR = PADDR_int;

always@(posedge CLK, negedge RESETn)
begin
	if (RESETn == 1'b0)
		begin
		apb_fsm_current_state 		<= Idle;
		PSEL 						<= 1'b0;
		PWRITE 						<= 1'b0;
		i 							<= 7'b0;
		DRAM_Ready 					<= 1'b0;
		end
	else
		begin
		case(apb_fsm_current_state)
		Idle:
		begin
			PSEL 					<= 1'b1;
			PENABLE 				<= 1'b0;
			PADDR_int 				<= 14'b00001000000000;			
			PWDATA 					<= DDRC_Reg[i];
			PWRITE 					<= 1'b1;
			apb_fsm_current_state 	<= Write_0;
		end
		Write_0:
		begin
			if(PREADY == 1'b1)
			begin
			PENABLE 				<= 1'b1;
			i 						<= i + 1'b1;			
			apb_fsm_current_state 	<= Write_1;
			end
		else
			begin
			apb_fsm_current_state 	<= Write_0;
			end
		end
		Write_1:
		begin
		if(i <= 56)
			begin
			PENABLE 				<= 1'b0;
			PADDR_int 				<= PADDR_int+1'b1;						
			PWDATA 					<= DDRC_Reg[i];
			apb_fsm_current_state 	<= Write_0;
			end
		else
			begin
			PENABLE 				<= 1'b0;			
			PADDR_int 				<= 14'b00001010001000;//0x220
			apb_fsm_current_state 	<= Write_2;
			end
		end
		Write_2:
		begin
		if(i <= 119)
			begin
			PENABLE 				<= 1'b0;
			PADDR_int 				<= PADDR_int+1'b1;
			i 						<= i + 1'b1;			
			PWDATA 					<= DDRC_Reg[i];
			apb_fsm_current_state 	<= Write_3;
			end
		else
			begin
			PENABLE 				<= 1'b0;
			PWRITE 					<= 1'b0;			
			PADDR_int 				<= 14'b00001000111001;//DDRC_SR
			apb_fsm_current_state 	<= Read_0;
			count_delay 			<= 12'b0;
			end
		end
		Write_3:
		begin
		if(PREADY == 1'b1)
			begin
			PENABLE 				<= 1'b1;			
			apb_fsm_current_state 	<= Write_2;
			end
		else
			begin
			apb_fsm_current_state 	<= Write_3;
			end
		end
		Read_0:
		begin
		if(PREADY == 1'b1 && count_delay > 12'b111111110000)
			begin
			PENABLE 				<= 1'b1;
			DRAM_Ready 				<= 1'b1;
			apb_fsm_current_state 	<= Read_1;
			end
		else
			begin
			count_delay 			<= count_delay + 1'b1;
			apb_fsm_current_state 	<= Read_0;
			end
		end
		Read_1:
		begin
		PENABLE 					<= 1'b0;
		end
		endcase
	end		
end

endmodule












