module openFPGA_Pocket_Analogizer #(parameter MASTER_CLK_FREQ=50_000_000) (
	input wire i_clk,
    input wire i_rst,
	input wire i_ena,
	//Video interface
	input wire [3:0] analog_video_type,
	input wire [7:0] R,
	input wire [7:0] G,
	input wire [7:0] B,
	input wire Hblank,
	input wire Vblank,
	input wire BLANKn,
	input wire Hsync,
	input wire Vsync,
	input wire Csync,
	input wire video_clk,
	//Video Y/C Encoder interface
	input wire PALFLAG,
	//input wire CVBS,
	input wire MULFLAG,
	input wire [4:0] CHROMA_ADD,
	input wire [4:0] CHROMA_MULT,
	input wire [39:0] CHROMA_PHASE_INC,
	input wire [26:0] COLORBURST_RANGE,
	//Video SVGA Scandoubler interface
	input wire [2:0] ce_divider,
	//SNAC interface
    input wire conf_AB,              //0 conf. A(default), 1 conf. B (see graph above)
    input wire [4:0] game_cont_type, //0-15 Conf. A, 16-31 Conf. B
    output wire [15:0] p1_btn_state,
    output wire [15:0] p2_btn_state,
    output wire [15:0] p3_btn_state,
    output wire [15:0] p4_btn_state,
	output wire busy, 
	//Pocket Analogizer IO interface to the cartridge port
	inout   wire    [7:0]   cart_tran_bank2,
	output  wire            cart_tran_bank2_dir,
	inout   wire    [7:0]   cart_tran_bank3,
	output  wire            cart_tran_bank3_dir,
	inout   wire    [7:0]   cart_tran_bank1,
	output  wire            cart_tran_bank1_dir,
	inout   wire    [7:4]   cart_tran_bank0,
	output  wire            cart_tran_bank0_dir,
	inout   wire            cart_tran_pin30,
	output  wire            cart_tran_pin30_dir,
	output  wire            cart_pin30_pwroff_reset,
	inout   wire            cart_tran_pin31,
	output  wire            cart_tran_pin31_dir,
    //debug
    output wire o_stb
);
	wire [7:4] CART_BK0_OUT ;
    wire [7:4] CART_BK0_IN ;
    wire CART_BK0_DIR ; 
    wire [7:6] CART_BK1_OUT_P76 ;
    wire CART_PIN30_OUT ;
    wire CART_PIN30_IN ;
    wire CART_PIN30_DIR ; 
    wire CART_PIN31_OUT ;
    wire CART_PIN31_IN ;
    wire CART_PIN31_DIR ;

	openFPGA_Pocket_Analogizer_SNAC #(.MASTER_CLK_FREQ(MASTER_CLK_FREQ)) snac
	(
		.i_clk(i_clk),
		.i_rst(i_rst),
		.conf_AB(conf_AB),              //0 conf. A(default), 1 conf. B (see graph above)
		.game_cont_type(game_cont_type), //0-15 Conf. A, 16-31 Conf. B
		//.game_cont_sample_rate(game_cont_sample_rate), //0 compatibility mode (slowest), 1 normal mode, 2 fast mode, 3 superfast mode
		.p1_btn_state(p1_btn_state),
		.p2_btn_state(p2_btn_state),
		.p3_btn_state(p3_btn_state),
		.p4_btn_state(p4_btn_state),
		.busy(busy),    
		//SNAC Pocket cartridge port interface (see graph above)   
		.CART_BK0_OUT(CART_BK0_OUT),
		.CART_BK0_IN(CART_BK0_IN),
		.CART_BK0_DIR(CART_BK0_DIR), 
		.CART_BK1_OUT_P76(CART_BK1_OUT_P76),
		.CART_PIN30_OUT(CART_PIN30_OUT),
		.CART_PIN30_IN(CART_PIN30_IN),
		.CART_PIN30_DIR(CART_PIN30_DIR), 
		.CART_PIN31_OUT(CART_PIN31_OUT),
		.CART_PIN31_IN(CART_PIN31_IN),
		.CART_PIN31_DIR(CART_PIN31_DIR),
		//debug
    	.o_stb(o_stb)
	); 

	//Choose type of analog video type of signal
	reg [5:0] Rout, Gout, Bout;
	reg HsyncOut, VsyncOut, BLANKnOut;
	wire [7:0] Yout, PrOut, PbOut;
	wire [5:0] R_Sd, G_Sd, B_Sd;
	wire Hsync_Sd, Vsync_Sd;
	wire Hblank_Sd, Vblank_Sd;
	wire BLANKn_SD = ~(Hblank_Sd || Vblank_Sd);

	always @(*) begin
		case(analog_video_type)
			4'h0, 4'h8: begin //RGBS
				Rout = R[7:2]&{6{BLANKn}};
				Gout = G[7:2]&{6{BLANKn}};
				Bout = B[7:2]&{6{BLANKn}};
				HsyncOut = Csync;
				VsyncOut = 1'b1;
				BLANKnOut = BLANKn;
			end
			4'h3, 4'h4, 4'hB, 4'hC: begin// Y/C Modes works for Analogizer R1, R2 Adapters
				Rout = yc_o[23:18];
				Gout = yc_o[15:10];
				Bout = yc_o[7:2];
				HsyncOut = yc_cs;
				VsyncOut = 1'b1;
				BLANKnOut = 1'b1;
			end
			4'h1, 4'h9: begin //RGsB
				Rout = R[7:2]&{6{BLANKn}};
				Gout = G[7:2]&{6{BLANKn}};
				Bout = B[7:2]&{6{BLANKn}};
				HsyncOut = 1'b1;
				VsyncOut = Csync; //to DAC SYNC pin, SWITCH SOG ON
				BLANKnOut = BLANKn;
			end
			4'h2, 4'hA: begin //YPbPr
				Rout = PrOut[7:2];
				Gout = Yout[7:2];
				Bout = PbOut[7:2];
				HsyncOut = 1'b1;
				VsyncOut = YPbPr_sync; //to DAC SYNC pin, SWITCH SOG ON
				BLANKnOut = 1'b1; //ADV7123 needs this
			end
			4'h5, 4'hD: begin //Scandoubler modes
				Rout = R_Sd;
				Gout = G_Sd;
				Bout = B_Sd;
				HsyncOut = Hsync_Sd;
				VsyncOut = Vsync_Sd;
				BLANKnOut = 1'b1;
			end
			default: begin
				Rout = 6'h0;
				Gout = 6'h0;
				Bout = 6'h3F;
				HsyncOut = Hsync;
				VsyncOut = 1'b1;
				BLANKnOut = BLANKn;
			end
		endcase
	end

	wire YPbPr_sync, YPbPr_blank;
	vga_out ybpr_video
	(
		.clk(video_clk),
		.ypbpr_en(1'b1),
		.csync(Csync),
		.de(BLANKn),
		.din({R&{8{BLANKn}},G&{8{BLANKn}},B&{8{BLANKn}}}), //NES specific override, because not zero color data while blanking period.
		.dout({PrOut,Yout,PbOut}),
		.csync_o(YPbPr_sync),
		.de_o(YPbPr_blank)
	);

	wire [23:0] yc_o;
	//wire yc_hs, yc_vs, 
	wire yc_cs;
	yc_out yc_out
	(
		.clk(i_clk),
		.PAL_EN(PALFLAG),
		.CVBS(1'b0),
		.PHASE_INC(CHROMA_PHASE_INC),
		.COLORBURST_RANGE(COLORBURST_RANGE),
		.MULFLAG(MULFLAG),
		.CHRADD(CHROMA_ADD), //fine tune 0-31
		.CHRMUL(CHROMA_MULT), //fine tune 0-31
		.hsync(Hsync),
		.vsync(Vsync),
		.csync(Csync),
		.dout(yc_o),
		//.din(rgb_color_r),
    	.din({R&{8{BLANKn}},G&{8{BLANKn}},B&{8{BLANKn}}}),
		.hsync_o(),
		.vsync_o(),
		.csync_o(yc_cs)
	);


	//delay hsync one pixel clock period
	// reg [1:0] delayed_hsync = 0;
	// reg pclk_r = 0;
	// always @(posedge i_clk) begin
	// 	pclk_r <= video_clk;
	// 	if(!pclk_r && video_clk) begin
	// 		delayed_hsync[0] <= Hsync;
	// 		delayed_hsync[1] <= delayed_hsync[0];
	// 	end
	// end
	scandoubler sc_video
	(
		// system interface
		.clk_sys(i_clk),
		.bypass(1'b0),

		// Pixelclock
		.ce_divider(ce_divider), // 0 - clk_sys/4, 1 - clk_sys/2, 2 - clk_sys/3, 3 - clk_sys/4, etc.
		//.ce_divider(3'd0), // 0 - clk_sys/4, 1 - clk_sys/2, 2 - clk_sys/3, 3 - clk_sys/4, etc.
		.pixel_ena(), //output
		.scanlines(2'd2), // scanlines (00-none 01-25% 10-50% 11-75%)

		// shifter video interface
		.hb_in(Hblank),
		.vb_in(Vblank),
		.hs_in(Hsync),
		//.hs_in(delayed_hsync[1]),
		.vs_in(Vsync),
		.r_in({R[7:2]&{6{BLANKn}}}),
		.g_in({G[7:2]&{6{BLANKn}}}),
		.b_in({B[7:2]&{6{BLANKn}}}),

		// output interface
		.hb_out(Hblank_Sd),
		.vb_out(Vblank_Sd),
		.hs_out(Hsync_Sd),
		.vs_out(Vsync_Sd),
		.r_out(R_Sd),
		.g_out(G_Sd),
		.b_out(B_Sd)
	);

	//infer tri-state buffers for cartridge data signals
	//BK0
	assign cart_tran_bank0         = i_rst | ~i_ena ? 4'hf : ((CART_BK0_DIR) ? CART_BK0_OUT : 4'hZ);     //on reset state set ouput value to 4'hf
	assign cart_tran_bank0_dir     = i_rst | ~i_ena ? 1'b1 : CART_BK0_DIR;                              //on reset state set pin dir to output
	assign CART_BK0_IN             = cart_tran_bank0;
	//BK3
	assign cart_tran_bank3         = i_rst | ~i_ena ? 8'hzz : {Rout[5:0],HsyncOut,VsyncOut};                          //on reset state set ouput value to 8'hZ
	assign cart_tran_bank3_dir     = i_rst | ~i_ena ? 1'b0  : 1'b1;                                     //on reset state set pin dir to input
	//BK2
	assign cart_tran_bank2         = i_rst | ~i_ena ? 8'hzz : {Bout[0],BLANKnOut,Gout[5:0]};                          //on reset state set ouput value to 8'hZ
	assign cart_tran_bank2_dir     = i_rst | ~i_ena ? 1'b0  : 1'b1;                                     //on reset state set pin dir to input
	//BK1
	assign cart_tran_bank1         = i_rst | ~i_ena ? 8'hzz : {CART_BK1_OUT_P76,video_clk,Bout[5:1]};      //on reset state set ouput value to 8'hZ
	assign cart_tran_bank1_dir     = i_rst | ~i_ena ? 1'b0  : 1'b1;                                     //on reset state set pin dir to input
	//PIN30
	assign cart_tran_pin30         = i_rst | ~i_ena ? 1'bz : ((CART_PIN30_DIR) ? CART_PIN30_OUT : 1'bZ); //on reset state set ouput value to 4'hf
	assign cart_tran_pin30_dir     = i_rst | ~i_ena ? 1'b0 : CART_PIN30_DIR;                              //on reset state set pin dir to output
	assign CART_PIN30_IN           = cart_tran_pin30;
	assign cart_pin30_pwroff_reset = i_rst | ~i_ena ? 1'b0 : 1'b1;                                      //1'b1 (GPIO USE)
	//PIN31
	assign cart_tran_pin31         = i_rst | ~i_ena ? 1'bz : ((CART_PIN31_DIR) ? CART_PIN31_OUT : 1'bZ); //on reset state set ouput value to 4'hf
	assign cart_tran_pin31_dir     = i_rst | ~i_ena ? 1'b0 : CART_PIN31_DIR;                            //on reset state set pin dir to input
	assign CART_PIN31_IN           = cart_tran_pin31;
endmodule