
module vip_config
(
	input             clk,
	input             reset,
	
	input       [7:0] ARX,
	input       [7:0] ARY,
	input             CFG_SET,

	input      [11:0] WIDTH,
	input      [11:0] HFP,
	input      [11:0] HBP,
	input      [11:0] HS,
	input      [11:0] HEIGHT,
	input      [11:0] VFP,
	input      [11:0] VBP,
	input      [11:0] VS,
	
	input      [11:0] VSET,

	output reg  [8:0] address,
	output reg        write,
	output reg [31:0] writedata,
	input             waitrequest
);


reg         newres = 1;

wire [21:0] init[23] =
'{
	//video mode
	{newres, 2'd2, 7'd04, 12'd0  }, //Bank
	{newres, 2'd2, 7'd30, 12'd0  }, //Valid
	{newres, 2'd2, 7'd05, 12'd0  }, //Progressive/Interlaced
	{newres, 2'd2, 7'd06, w      }, //Active pixel count
	{newres, 2'd2, 7'd07, h      }, //Active line count
	{newres, 2'd2, 7'd09, hfp    }, //Horizontal Front Porch
	{newres, 2'd2, 7'd10, hs     }, //Horizontal Sync Length
	{newres, 2'd2, 7'd11, hb     }, //Horizontal Blanking (HFP+HBP+HSync)
	{newres, 2'd2, 7'd12, vfp    }, //Vertical Front Porch
	{newres, 2'd2, 7'd13, vs     }, //Vertical Sync Length
	{newres, 2'd2, 7'd14, vb     }, //Vertical blanking (VFP+VBP+VSync)
	{newres, 2'd2, 7'd30, 12'd1  }, //Valid
	{newres, 2'd2, 7'd00, 12'd1  }, //Go

	//mixer
	{  1'd1, 2'd1, 7'd03, w      }, //Bkg Width
	{  1'd1, 2'd1, 7'd04, h      }, //Bkg Height
	{  1'd1, 2'd1, 7'd08, posx   }, //Pos X
	{  1'd1, 2'd1, 7'd09, posy   }, //Pos Y
	{  1'd1, 2'd1, 7'd10, 12'd1  }, //Enable Video 0
	{  1'd1, 2'd1, 7'd00, 12'd1  }, //Go

	//scaler
	{  1'd1, 2'd0, 7'd03, videow }, //Output Width
	{  1'd1, 2'd0, 7'd04, videoh }, //Output Height
	{  1'd1, 2'd0, 7'd00, 12'd1  }, //Go

	22'h3FFFFF
};

reg [11:0] w;
reg [11:0] hfp;
reg [11:0] hbp;
reg [11:0] hs;
reg [11:0] hb;
reg [11:0] h;
reg [11:0] vfp;
reg [11:0] vbp;
reg [11:0] vs;
reg [11:0] vb;

reg [11:0] videow;
reg [11:0] videoh;

reg [11:0] posx;
reg [11:0] posy;

always @(posedge clk) begin
	reg  [7:0] state = 0;
	reg  [7:0] arx, ary;
	reg  [7:0] arxd, aryd;
	reg [11:0] vset, vsetd;
	reg        cfg, cfgd;
	reg [31:0] wcalc;
	reg [31:0] hcalc;
	reg [12:0] timeout = 0;

	arxd  <= ARX;
	aryd  <= ARY;
	vsetd <= VSET;
	
	cfg   <= CFG_SET;
	cfgd  <= cfg;

	write <= 0;
	if(reset || (arx != arxd) || (ary != aryd) || (vset != vsetd) || (~cfgd && cfg)) begin
		arx <= arxd;
		ary <= aryd;
		vset <= vsetd;
		timeout <= '1;
		state <= 0;
		if(reset || (~cfgd && cfg)) newres <= 1;
	end
	else
	if(timeout > 0)
	begin
		timeout <= timeout - 1'd1;
		state <= 1;
		if(!(timeout & 'h1f)) case(timeout>>5)
			5:	begin
					w   <= WIDTH;
					hfp <= HFP;
					hbp <= HBP;
					hs  <= HS;
					h   <= HEIGHT;
					vfp <= VFP;
					vbp <= VBP;
					vs  <= VS;
				end
			4: begin
					hb  <= hfp+hbp+hs;
					vb  <= vfp+vbp+vs;
				end
			3: begin
					wcalc <= vset ? (vset*arx)/ary : (h*arx)/ary;
					hcalc <= (w*ary)/arx;
				end
			2: begin
					videow <= (!vset && (wcalc > w))    ? w : wcalc[11:0];
					videoh <= vset ? vset : (hcalc > h) ? h : hcalc[11:0];
				end
			1: begin
					posx <= (w - videow)>>1;
					posy <= (h - videoh)>>1;
				end
		endcase
	end
	else
	if(~waitrequest && state)
	begin
		state <= state + 1'd1;
		write <= 0;
		if((state&3)==3) begin
			if(init[state>>2] == 22'h3FFFFF) begin
				state  <= 0;
				newres <= 0;
			end
			else begin
				writedata <= 0;
				{write, address, writedata[11:0]} <= init[state>>2];
			end
		end
	end
end

endmodule
