// // // 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} // // altera message_off 10720 // altera message_off 12161 module video_mixer #( parameter LINE_LENGTH = 768, parameter HALF_DEPTH = 0, parameter GAMMA = 0 ) ( // video clock // it should be multiple by (ce_pix*4). input clk_vid, // 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, inout [21:0] gamma_bus, // 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; localparam DWIDTH_SD = GAMMA ? 7 : DWIDTH; localparam HALF_DEPTH_SD = GAMMA ? 0 : HALF_DEPTH; generate if(GAMMA && HALF_DEPTH) begin wire [7:0] R_in = mono ? {G,R} : {R,R}; wire [7:0] G_in = mono ? {G,R} : {G,G}; wire [7:0] B_in = mono ? {G,R} : {B,B}; end else begin wire [DWIDTH:0] R_in = R; wire [DWIDTH:0] G_in = G; wire [DWIDTH:0] B_in = B; end endgenerate wire hs_g, vs_g; wire hb_g, vb_g; wire [DWIDTH_SD:0] R_gamma, G_gamma, B_gamma; generate if(GAMMA) begin assign gamma_bus[21] = 1; gamma_corr gamma( .clk_sys(gamma_bus[20]), .clk_vid(clk_vid), .ce_pix(ce_pix), .gamma_en(gamma_bus[19]), .gamma_wr(gamma_bus[18]), .gamma_wr_addr(gamma_bus[17:8]), .gamma_value(gamma_bus[7:0]), .HSync(HSync), .VSync(VSync), .HBlank(HBlank), .VBlank(VBlank), .RGB_in({R_in,G_in,B_in}), .HSync_out(hs_g), .VSync_out(vs_g), .HBlank_out(hb_g), .VBlank_out(vb_g), .RGB_out({R_gamma,G_gamma,B_gamma}) ); end else begin assign gamma_bus[21] = 0; assign {R_gamma,G_gamma,B_gamma} = {R_in,G_in,B_in}; assign {hs_g, vs_g, hb_g, vb_g} = {HSync, VSync, HBlank, VBlank}; end endgenerate wire [DWIDTH_SD:0] R_sd; wire [DWIDTH_SD:0] G_sd; wire [DWIDTH_SD:0] B_sd; wire hs_sd, vs_sd, hb_sd, vb_sd, ce_pix_sd; scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH_SD)) sd ( .*, .hs_in(hs_g), .vs_in(vs_g), .hb_in(hb_g), .vb_in(vb_g), .r_in(R_gamma), .g_in(G_gamma), .b_in(B_gamma), .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_SD:0] rt = (scandoubler ? R_sd : R_gamma); wire [DWIDTH_SD:0] gt = (scandoubler ? G_sd : G_gamma); wire [DWIDTH_SD:0] bt = (scandoubler ? B_sd : B_gamma); generate if(!GAMMA && 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 : hs_g); wire vs = (scandoubler ? vs_sd : vs_g); assign ce_pix_out = scandoubler ? ce_pix_sd : ce_pix; reg scanline = 0; always @(posedge clk_vid) 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 : ~hb_g; wire vde = scandoubler ? ~vb_sd : ~vb_g; reg [7:0] v_r,v_g,v_b; reg v_vs,v_hs,v_de; always @(posedge clk_vid) begin reg old_hde; if(ce_pix_out) begin case(scanlines & {scanline, scanline}) 1: begin // reduce 25% = 1/2 + 1/4 v_r <= {1'b0, r[7:1]} + {2'b00, r[7:2]}; v_g <= {1'b0, g[7:1]} + {2'b00, g[7:2]}; v_b <= {1'b0, b[7:1]} + {2'b00, b[7:2]}; end 2: begin // reduce 50% = 1/2 v_r <= {1'b0, r[7:1]}; v_g <= {1'b0, g[7:1]}; v_b <= {1'b0, b[7:1]}; end 3: begin // reduce 75% = 1/4 v_r <= {2'b00, r[7:2]}; v_g <= {2'b00, g[7:2]}; v_b <= {2'b00, b[7:2]}; end default: begin v_r <= r; v_g <= g; v_b <= b; end endcase v_vs <= vs; v_hs <= hs; old_hde <= hde; if(~old_hde && hde) v_de <= vde; if(old_hde && ~hde) v_de <= 0; end end always @(posedge clk_vid) if(ce_pix_out) begin VGA_R <= v_r; VGA_G <= v_g; VGA_B <= v_b; VGA_HS <= v_hs; VGA_VS <= v_vs; VGA_DE <= v_de; end endmodule