TITLE "DDR_CTR_BLITTER";

-- CREATED BY FREDI ASCHWANDEN

INCLUDE "lpm_bustri_BYT.inc";


-- {{ALTERA_PARAMETERS_BEGIN}} DO NOT REMOVE THIS LINE!
-- {{ALTERA_PARAMETERS_END}} DO NOT REMOVE THIS LINE!

SUBDESIGN DDR_CTR_BLITTER
(
	-- {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
	FB_ADR[31..0] : INPUT;
	nFB_CS1 : INPUT;
	nFB_CS2 : INPUT;
	nFB_CS3 : INPUT;
	nFB_OE : INPUT;
	FB_SIZE0 : INPUT;
	FB_SIZE1 : INPUT;
	nRSTO : INPUT;
	MAIN_CLK : INPUT;
	FIFO_FULL : INPUT;
	FB_ALE : INPUT;
	nFB_WR : INPUT;
	DDR_SYNC_66M : INPUT;
	VSYNC : INPUT;
	BLITTER_ON : INPUT;
	VIDEO_RAM_CTR[15..0] : INPUT;
	VDVZ[127..0] : INPUT;
	DDRCLK[3..0] : INPUT;
	BA0 : OUTPUT;
	BA1 : OUTPUT;
	VA[12..0] : OUTPUT;
	nVWE : OUTPUT;
	nVRAS : OUTPUT;
	nVCS : OUTPUT;
	VCKE : OUTPUT;
	nVCAS : OUTPUT;
	FIFO_WRE : OUTPUT;
	FB_LE[3..0] : OUTPUT;
	FB_VDOE[3..0] : OUTPUT;
	START_CYC_RDWR : OUTPUT;
	DDR_WR : OUTPUT;
	CLEAR_FIFO_CNT : OUTPUT;
	BLITTER_RUN : OUTPUT;
	BLITTER_DOUT[127..0] : OUTPUT;
	BLITTER_LE[3..0] : OUTPUT;
	BLITTER_RDE : OUTPUT;
	DDRWR_D_SEL[1..0] : OUTPUT;
	VDMP[7..0] : OUTPUT;
	FB_AD[31..0] : BIDIR;
	-- {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
)

VARIABLE
	FB_REGDDR				:MACHINE WITH STATES(FR_WAIT,FR_S0,FR_S1,FR_S2,FR_S3);
	DDR_SM					:MACHINE WITH STATES(DS_T1,DS_T2,DS_T3,DS_T4,DS_T5,DS_T6,DS_T7,DS_T8,DS_LS);
	LINE					:NODE;
	FB_B[3..0]				:NODE;
	VCAS					:NODE;
	VRAS					:NODE;
	VWE						:NODE;
	VA[12..0]				:NODE;
	BA0						:NODE;
	BA1						:NODE;
	DDR_WR					:DFF;
	DDR_SEL					:NODE;
	DDR_CONFIG				:NODE;
	DDRWR_D_SEL[1..0]		:DFF;
	CPU_ROW_ADR[12..0]		:NODE;
	CPU_BA0					:NODE;
	CPU_BA1					:NODE;
	CPU_COL_ADR[9..0]		:NODE;
	CPU_SIG					:NODE;
	CPU_REQ					:DFF;
	BLITTER_SIG				:NODE;
	BLITTER_REQ				:DFF;
	BLITTER_RUN				:DFF;
	BLITTER_WR				:DFF;
	BLITTER_ROW_ADR[12..0]	:NODE;
	BLITTER_BA0				:NODE;
	BLITTER_BA1				:NODE;
	BLITTER_COL_ADR[9..0]	:NODE;
	FIFO_SIG				:NODE;
	FIFO_REQ				:DFF;
	FIFO_ROW_ADR[12..0]		:NODE;
	FIFO_BA0				:NODE;
	FIFO_BA1				:NODE;
	FIFO_COL_ADR[9..0]		:NODE;
	FIFO_WRE				:DFF;
	FIFO_ACTIVE				:NODE;
	CLEAR_FIFO_CNT			:DFF;
	STOP					:DFF;
	DDR_REFRESH_ON			:NODE;
	VIDEO_BASE_L_D[3..0]	:DFFE;
	VIDEO_BASE_L			:NODE;
	VIDEO_BASE_M_D[7..0]	:DFFE;
	VIDEO_BASE_M			:NODE;
	VIDEO_BASE_H_D[7..0]	:DFFE;
	VIDEO_BASE_H			:NODE;
	VIDEO_BASE_X_D[7..0]	:DFFE;
	VIDEO_ADR_CNT[27..0]	:DFFE;
	VIDEO_CNT_L				:NODE;
	VIDEO_CNT_M				:NODE;
	VIDEO_CNT_H				:NODE;
	VIDEO_BASE_ADR[27..0]	:NODE;
	
BEGIN
	LINE =  FB_SIZE0 &  FB_SIZE1;
-- BYT SELECT
	FB_B0 = FB_ADR[1..0]==0;								-- ADR==0
	FB_B1 = FB_ADR[1..0]==1									-- ADR==1
		  # FB_SIZE1 & !FB_SIZE0 & !FB_ADR1					-- HIGH WORD
		  # FB_SIZE1 & FB_SIZE0 # !FB_SIZE1 & !FB_SIZE0; 	-- LONG UND LINE
	FB_B2 = FB_ADR[1..0]==2									-- ADR==2
		  # FB_SIZE1 & FB_SIZE0 # !FB_SIZE1 & !FB_SIZE0; 	-- LONG UND LINE
	FB_B3 = FB_ADR[1..0]==3									-- ADR==3
		  # FB_SIZE1 & !FB_SIZE0 &  FB_ADR1 				-- LOW WORD
		  # FB_SIZE1 & FB_SIZE0 # !FB_SIZE1 & !FB_SIZE0; 	-- LONG UND LINE
-- CPU READ (REG DDR => CPU) AND WRITE (CPU => REG DDR)  --------------------------------------------------
	FB_REGDDR.CLK = MAIN_CLK;
	CASE FB_REGDDR IS
		WHEN FR_WAIT => 
			IF DDR_SEL THEN
				FB_REGDDR = FR_S0;
			ELSE
				FB_REGDDR = FR_WAIT;
			END IF;
		WHEN FR_S0 =>
			FB_VDOE0 = !nFB_OE & !DDR_CONFIG;
			FB_LE0   = !nFB_WR;
			IF LINE THEN							
				FB_REGDDR = FR_S1;
			ELSE
				FB_REGDDR = FR_WAIT;
			END IF;
		WHEN FR_S1 => 
			FB_VDOE1 = !nFB_OE & !DDR_CONFIG;
			FB_LE1   = !nFB_WR;
			FB_REGDDR = FR_S2;
		WHEN FR_S2 => 
			FB_VDOE2 = !nFB_OE & !DDR_CONFIG;
			FB_LE2   = !nFB_WR;
			FB_REGDDR = FR_S3;
		WHEN FR_S3 => 
			FB_VDOE3 = !nFB_OE & !DDR_CONFIG;
			FB_LE3   = !nFB_WR;
			FB_REGDDR = FR_WAIT;
	END CASE;
-- DDR STEUERUNG -----------------------------------------------------
-- VIDEO RAM CONTROL REGISTER (IST IN VIDEO_MUX_CTR) $F0000400: BIT 0=VCKE,1=!nVCS,2=FIFO_ACTIVE,3=FIFO UND CNT CLEAR,15..11=VIDEO RAM BASE
	VCKE = VIDEO_RAM_CTR0;
	nVCS = !VIDEO_RAM_CTR1;
	FIFO_ACTIVE = VIDEO_RAM_CTR2;
	DDR_CONFIG = VIDEO_RAM_CTR3;	
	DDR_REFRESH_ON = VIDEO_RAM_CTR4;
--------------------------------
	CPU_ROW_ADR[] = FB_ADR[26..14];
	CPU_BA1 = FB_ADR13;
	CPU_BA0 = FB_ADR12;
	CPU_COL_ADR[] = FB_ADR[11..2];
	nVRAS = !VRAS;
	nVCAS = !VCAS;
	nVWE = !VWE;
	DDR_WR.CLK = DDRCLK0;
-- SELECT LOGIC
	DDR_SEL  =  FB_ALE & FB_AD[31..29]==B"011";
-- WENN READ ODER WRITE B,W,L DDR SOFORT ANFORDERN, BEI WRITE LINE SPÄTER
	CPU_SIG = DDR_SEL &  nFB_WR & !DDR_CONFIG						-- READ SOFORT LOS
			# FR_S0   & !nFB_WR 		   							-- WRITE SPÄTER AUCH CONFIG
			# FR_S3   & !nFB_WR &  LINE  & !DDR_CONFIG;				-- LINE WRITE
	CPU_REQ = CPU_SIG;
	CPU_REQ.CLK = DDR_SYNC_66M;
	DDR_D_SEL[].CLK = DDRCLK3;
-- DDR STATE MACHINE  -----------------------------------------------
	DDR_SM.CLK = DDRCLK0;
	CASE DDR_SM IS
		WHEN DS_T1 =>
			IF MAIN_CLK THEN
				DDR_WR = DDR_WR;									-- WRITE HALTEN (VON T4)
				DDR_SM = DS_T2;
			ELSE
				DDR_SM = DS_LS;										-- SYNCHRONISIEREN
			END IF;
		WHEN DS_T2 =>
			IF !DDR_CONFIG THEN
				VRAS  = CPU_SIG # BLITTER_SIG # FIFO_SIG # DDR_REFRESH_ON;
				VA[]  = CPU_SIG 	& CPU_ROW_ADR[]
					#  BLITTER_SIG & BLITTER_ROW_ADR[]
					#  FIFO_SIG 	& FIFO_ROW_ADR[];
				BA0   = CPU_SIG 	& CPU_BA0
					#  BLITTER_SIG & BLITTER_BA0
					#  FIFO_SIG 	& FIFO_BA0;
				BA1   = CPU_SIG 	& CPU_BA1
					#  BLITTER_SIG & BLITTER_BA1
					#  FIFO_SIG 	& FIFO_BA1;
				VCAS = !CPU_SIG & !BLITTER_SIG & !FIFO_SIG & DDR_REFRESH_ON;		-- AUTO REFRESH WENN SONST NICHTS
				BLITTER_REQ = BLITTER_SIG;
				FIFO_REQ = FIFO_SIG;	
			END IF;
			IF MAIN_CLK THEN
				DDR_SM = DS_T3;
			ELSE
				DDR_SM = DS_LS;
			END IF;
		WHEN DS_T3 =>
			IF DDR_CONFIG & CPU_REQ THEN
				VRAS = FB_AD18;
				VCAS = FB_AD17;
				VWE	 = FB_AD16;
				BA1  = FB_AD14;
				BA0  = FB_AD13;
				VA[] = FB_AD[12..0];
			END IF;
			IF !CPU_REQ & !BLITTER_REQ & !FIFO_REQ # DDR_CONFIG THEN
				DDR_SM = DS_LS;
			ELSE
				BLITTER_REQ = BLITTER_SIG;
				FIFO_REQ = FIFO_SIG;						
				DDR_SM = DS_T4;
			END IF;
		WHEN DS_T4 =>
			FIFO_REQ = FIFO_SIG;	
			VCAS = VCC;															
			VWE  = !nFB_WR & CPU_REQ # BLITTER_WR & BLITTER_REQ;
			VA[9..0] = CPU_REQ     & CPU_COL_ADR[]
					# BLITTER_REQ & BLITTER_COL_ADR[]
					# FIFO_REQ    & FIFO_COL_ADR[];
			VA10 = VCC;															-- AUTO PRECHARGE
			BA0 = CPU_REQ     & CPU_BA0
				# BLITTER_REQ & BLITTER_BA0
				# FIFO_REQ    & FIFO_BA0;
			BA1 = CPU_REQ     & CPU_BA1
				# BLITTER_REQ & BLITTER_BA1
				# FIFO_REQ    & FIFO_BA1;
			DDR_WR         = !nFB_WR & CPU_REQ # BLITTER_WR & BLITTER_REQ;
			FIFO_REQ = FIFO_SIG;						
			IF FIFO_REQ & FIFO_COL_ADR[]!= H"3FF" THEN							-- GLEICHE PAGE?
				DDR_SM = DS_T5;													-- JA->
			ELSE
				DDR_SM = DS_T1;													-- SONST NEUE PAGE AUFMACHEN
			END IF;
		WHEN DS_T5 =>
			FIFO_REQ = FIFO_SIG;	
			DDR_SM = DS_T6;
		WHEN DS_T6 =>								 
			IF CPU_SIG THEN															-- SOFORT UMSCHALTEN WENN CPU REQ
				VRAS = VCC;
				VA[] = CPU_ROW_ADR[];
				BA1  = CPU_BA1;
				BA0  = CPU_BA0;
				DDR_SM = DS_T3;
			ELSE
				FIFO_REQ = FIFO_SIG;	
				VCAS = VCC;															
				VA[9..0] = FIFO_COL_ADR[];
				VA10 = VCC;															-- AUTO PRECHARGE
				BA0 = FIFO_BA0;
				BA1 = FIFO_BA1;
				FIFO_WRE 	   =  FIFO_REQ;											-- ODER FIFO LATCH IN 5 CYC 133
				IF FIFO_REQ & FIFO_COL_ADR[]!= H"3FF" THEN							-- GLEICHE PAGE?
					DDR_SM = DS_T5;													-- JA->
				ELSE
					DDR_SM = DS_T1;													-- SONST NEUE PAGE AUFMACHEN
				END IF;
			END IF;
		WHEN DS_LS =>
			IF !MAIN_CLK THEN														-- LEERSTATE UND SYNC
				DDR_SM = DS_T1;	
			ELSE
				DDR_SM = DS_LS;	
			END IF;
	END CASE;
------------------------------------------------------------------------------	
-- FIFO ---------------------------------
	FIFO_SIG = FIFO_ACTIVE & !FIFO_FULL & !BLITTER_SIG & !CPU_SIG;
	FIFO_REQ.CLK = DDR_SYNC_66M;
	FIFO_ROW_ADR[] = VIDEO_ADR_CNT[24..12];
	FIFO_BA1 	   = VIDEO_ADR_CNT11;
	FIFO_BA0 	   = VIDEO_ADR_CNT10;
	FIFO_COL_ADR[] = VIDEO_ADR_CNT[9..0];
	-- ZÄHLER RÜCKSETZEN WENN VSYNC ----------------
	CLEAR_FIFO_CNT.CLK  = DDRCLK0;
	CLEAR_FIFO_CNT = VSYNC # !FIFO_ACTIVE;
	STOP.CLK = DDRCLK0;
	STOP = VSYNC # CLEAR_FIFO_CNT;
	VIDEO_ADR_CNT[].CLK = DDRCLK0;
	VIDEO_ADR_CNT[] =   CLEAR_FIFO_CNT & VIDEO_BASE_ADR[]			-- SET 
					 # !CLEAR_FIFO_CNT & (VIDEO_ADR_CNT[]+1);		-- NEXT 16 BYTS
	VIDEO_ADR_CNT[].ENA = CLEAR_FIFO_CNT # FIFO_WRE;
	FIFO_WRE.CLK = DDRCLK0;
---------------------------------------------------------------
-- BLITTER BUS IST 128 BIT BREIT ------
	BLITTER_SIG = GND & !CPU_SIG;
	BLITTER_REQ.CLK = DDR_SYNC_66M;
	BLITTER_RUN.CLK = DDRCLK0;
	BLITTER_RUN = GND;
	BLITTER_WR.CLK = DDRCLK0;
	BLITTER_WR = GND;
	DDRWR_D_SEL1 = BLITTER_WR;
	BLITTER_ROW_ADR[] = H"0";
	BLITTER_BA1 = GND;
	BLITTER_BA0 = GND;
	BLITTER_COL_ADR[] = H"0";
	BLITTER_DOUT[] = H"0";
	BLITTER_LE[] = H"0";
-----------------------------------------------------------	
-- VIDEO REGISTER -----------------------
---------------------------------------------------------------------------------------------------------------------
	VIDEO_BASE_L_D[].CLK = MAIN_CLK;
	VIDEO_BASE_L = !nFB_CS1 & FB_ADR[15..1]==H"4106"; 								-- 820D/2
	VIDEO_BASE_L_D[] = FB_AD[23..20];												-- SORRY, NUR 16 BYT GRENZEN
	VIDEO_BASE_L_D[].ENA = !nFB_WR & VIDEO_BASE_L & FB_B1;	

	VIDEO_BASE_M_D[].CLK = MAIN_CLK;
	VIDEO_BASE_M = !nFB_CS1 & FB_ADR[15..1]==H"4101"; 								-- 8203/2
	VIDEO_BASE_M_D[] = FB_AD[23..16];
	VIDEO_BASE_M_D[].ENA = !nFB_WR & VIDEO_BASE_M & FB_B3;	

	VIDEO_BASE_H_D[].CLK = MAIN_CLK;
	VIDEO_BASE_H = !nFB_CS1 & FB_ADR[15..1]==H"4100";			 					-- 8200-1/2
	VIDEO_BASE_H_D[] = FB_AD[23..16];
	VIDEO_BASE_H_D[].ENA = !nFB_WR & VIDEO_BASE_H & FB_B1;	
	VIDEO_BASE_X_D[].CLK = MAIN_CLK;
	VIDEO_BASE_X_D[] = FB_AD[31..24];
	VIDEO_BASE_X_D[].ENA = !nFB_WR & VIDEO_BASE_H & FB_B0;	

	VIDEO_CNT_L = !nFB_CS1 & FB_ADR[15..1]==H"4104"; 								-- 8209/2
	VIDEO_CNT_M = !nFB_CS1 & FB_ADR[15..1]==H"4103"; 								-- 8207/2
	VIDEO_CNT_H = !nFB_CS1 & FB_ADR[15..1]==H"4102"; 								-- 8205/2
					  
	FB_AD[31..24] = lpm_bustri_BYT(
						VIDEO_BASE_H     & VIDEO_BASE_X_D[] 
					  # VIDEO_CNT_H		 & VIDEO_ADR_CNT[27..20]
					  ,(VIDEO_BASE_H # VIDEO_CNT_H) & !nFB_OE);

	FB_AD[23..16] = lpm_bustri_BYT(
						VIDEO_BASE_L  & (VIDEO_BASE_L_D[],B"0000")
					  # VIDEO_BASE_M  &  VIDEO_BASE_M_D[]
					  # VIDEO_BASE_H  &  VIDEO_BASE_H_D[]
					  # VIDEO_CNT_L	  & (VIDEO_ADR_CNT[3..0],B"0000")
					  # VIDEO_CNT_M	  &  VIDEO_ADR_CNT[11..4]
					  # VIDEO_CNT_H	  &  VIDEO_ADR_CNT[19..12]
					  ,(VIDEO_BASE_L # VIDEO_BASE_M # VIDEO_BASE_H # VIDEO_CNT_L # VIDEO_CNT_M # VIDEO_CNT_H) & !nFB_OE);
						
	VIDEO_BASE_ADR[27..20] = VIDEO_BASE_X_D[];
	VIDEO_BASE_ADR[19..12] = VIDEO_BASE_H_D[];
	VIDEO_BASE_ADR[11..4]  = VIDEO_BASE_M_D[];
	VIDEO_BASE_ADR[3..0]   = VIDEO_BASE_L_D[];
END;

