//
//
// Copyright (c) 2017 Sorgelig
//
// This program is GPL Licensed. See COPYING for the full license.
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////

`timescale 1ns / 1ps

//
// LINE_LENGTH: Length of  display line in pixels
//              Usually it's length from HSync to HSync.
//              May be less if line_start is used.
//
// HALF_DEPTH:  If =1 then color dept is 4 bits per component
//              For half depth 8 bits monochrome is available with
//              mono signal enabled and color = {G, R}

module video_mixer
#(
	parameter LINE_LENGTH  = 768,
	parameter HALF_DEPTH   = 0
)
(
	// master clock
	// it should be multiple by (ce_pix*4).
	input            clk_sys,
	
	// Pixel clock or clock_enable (both are accepted).
	input            ce_pix,
	output           ce_pix_out,

	input            scandoubler,

	// scanlines (00-none 01-25% 10-50% 11-75%)
	input      [1:0] scanlines,

	// High quality 2x scaling
	input            hq2x,

	// color
	input [DWIDTH:0] R,
	input [DWIDTH:0] G,
	input [DWIDTH:0] B,

	// Monochrome mode (for HALF_DEPTH only)
	input            mono,

	// Positive pulses.
	input            HSync,
	input            VSync,
	input            HBlank,
	input            VBlank,

	// video output signals
	output reg [7:0] VGA_R,
	output reg [7:0] VGA_G,
	output reg [7:0] VGA_B,
	output reg       VGA_VS,
	output reg       VGA_HS,
	output reg       VGA_DE
);

localparam DWIDTH = HALF_DEPTH ? 3 : 7;

wire [DWIDTH:0] R_sd;
wire [DWIDTH:0] G_sd;
wire [DWIDTH:0] B_sd;
wire hs_sd, vs_sd, hb_sd, vb_sd, ce_pix_sd;

scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH)) sd
(
	.*,
	.hs_in(HSync),
	.vs_in(VSync),
	.hb_in(HBlank),
	.vb_in(VBlank),
	.r_in(R),
	.g_in(G),
	.b_in(B),

	.ce_pix_out(ce_pix_sd),
	.hs_out(hs_sd),
	.vs_out(vs_sd),
	.hb_out(hb_sd),
	.vb_out(vb_sd),
	.r_out(R_sd),
	.g_out(G_sd),
	.b_out(B_sd)
);

wire [DWIDTH:0] rt  = (scandoubler ? R_sd : R);
wire [DWIDTH:0] gt  = (scandoubler ? G_sd : G);
wire [DWIDTH:0] bt  = (scandoubler ? B_sd : B);

generate
	if(HALF_DEPTH) begin
		wire [7:0] r  = mono ? {gt,rt} : {rt,rt};
		wire [7:0] g  = mono ? {gt,rt} : {gt,gt};
		wire [7:0] b  = mono ? {gt,rt} : {bt,bt};
	end else begin
		wire [7:0] r  = rt;
		wire [7:0] g  = gt;
		wire [7:0] b  = bt;
	end
endgenerate

wire hs = (scandoubler ? hs_sd : HSync);
wire vs = (scandoubler ? vs_sd : VSync);

assign ce_pix_out = scandoubler ? ce_pix_sd : ce_pix;


reg scanline = 0;
always @(posedge clk_sys) begin
	reg old_hs, old_vs;
	
	old_hs <= hs;
	old_vs <= vs;
	
	if(old_hs && ~hs) scanline <= ~scanline;
	if(old_vs && ~vs) scanline <= 0;
end

wire hde = scandoubler ? ~hb_sd : ~HBlank;
wire vde = scandoubler ? ~vb_sd : ~VBlank;

always @(posedge clk_sys) begin
	reg old_hde;

	case(scanlines & {scanline, scanline})
		1: begin // reduce 25% = 1/2 + 1/4
			VGA_R <= {1'b0, r[7:1]} + {2'b00, r[7:2]};
			VGA_G <= {1'b0, g[7:1]} + {2'b00, g[7:2]};
			VGA_B <= {1'b0, b[7:1]} + {2'b00, b[7:2]};
		end

		2: begin // reduce 50% = 1/2
			VGA_R <= {1'b0, r[7:1]};
			VGA_G <= {1'b0, g[7:1]};
			VGA_B <= {1'b0, b[7:1]};
		end

		3: begin // reduce 75% = 1/4
			VGA_R <= {2'b00, r[7:2]};
			VGA_G <= {2'b00, g[7:2]};
			VGA_B <= {2'b00, b[7:2]};
		end

		default: begin
			VGA_R <= r;
			VGA_G <= g;
			VGA_B <= b;
		end
	endcase

	VGA_VS <= vs;
	VGA_HS <= hs;

	old_hde <= hde;
	if(~old_hde && hde && vde) VGA_DE <= 1;
	if(old_hde && ~hde) VGA_DE <= 0;
end

endmodule
