diff --git a/common/mist/cofi.sv b/common/mist/cofi.sv new file mode 100644 index 00000000..34f12ba8 --- /dev/null +++ b/common/mist/cofi.sv @@ -0,0 +1,56 @@ +// Composite-like horizontal blending by Kitrinx + +module cofi ( + input clk, + input pix_ce, + input enable, + + input hblank, + input vblank, + input hs, + input vs, + input [5:0] red, + input [5:0] green, + input [5:0] blue, + + output reg hblank_out, + output reg vblank_out, + output reg hs_out, + output reg vs_out, + output reg [5:0] red_out, + output reg [5:0] green_out, + output reg [5:0] blue_out +); + + function bit [5:0] color_blend ( + input [5:0] color_prev, + input [5:0] color_curr, + input blank_last + ); + begin + color_blend = blank_last ? color_curr : (color_prev >> 1) + (color_curr >> 1); + end + endfunction + +reg [5:0] red_last; +reg [5:0] green_last; +reg [5:0] blue_last; + +always @(posedge clk) if (pix_ce) begin + + hblank_out <= hblank; + vblank_out <= vblank; + vs_out <= vs; + hs_out <= hs; + + red_last <= red; + blue_last <= blue; + green_last <= green; + + red_out <= enable ? color_blend(red_last, red, hblank_out) : red; + blue_out <= enable ? color_blend(blue_last, blue, hblank_out) : blue; + green_out <= enable ? color_blend(green_last, green, hblank_out) : green; + +end + +endmodule diff --git a/common/mist/mist.qip b/common/mist/mist.qip index b5ad8ce4..27f8644d 100644 --- a/common/mist/mist.qip +++ b/common/mist/mist.qip @@ -5,6 +5,7 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mist_vi set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.sv] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv] set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) dac.vhd] diff --git a/common/mist/mist.vhd b/common/mist/mist.vhd index 711d6304..83ae9ff8 100644 --- a/common/mist/mist.vhd +++ b/common/mist/mist.vhd @@ -84,6 +84,7 @@ component mist_video scandoubler_disable : in std_logic; ypbpr : in std_logic; rotate : in std_logic_vector(1 downto 0); + blend : in std_logic; HSync : in std_logic; VSync : in std_logic; diff --git a/common/mist/mist2.qip b/common/mist/mist2.qip index a82ec0fe..cf389ff2 100644 --- a/common/mist/mist2.qip +++ b/common/mist/mist2.qip @@ -5,6 +5,7 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) mist_vi set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.sv] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sdram.sv] --set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) dpram.vhd] --set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) spram.vhd] diff --git a/common/mist/mist_video.v b/common/mist/mist_video.v index b5eda352..062e504b 100644 --- a/common/mist/mist_video.v +++ b/common/mist/mist_video.v @@ -24,6 +24,8 @@ module mist_video input ypbpr, // Rotate OSD [0] - rotate [1] - left or right input [1:0] rotate, + // composite-like blending + input blend, // video in input [COLOR_DEPTH-1:0] R, @@ -46,6 +48,7 @@ parameter OSD_X_OFFSET = 10'd0; parameter OSD_Y_OFFSET = 10'd0; parameter SD_HCNT_WIDTH = 9; parameter COLOR_DEPTH = 6; // 1-6 +parameter OSD_AUTO_CE = 1'b1; wire [5:0] SD_R_O; wire [5:0] SD_G_O; @@ -77,11 +80,35 @@ always @(*) begin end end +reg [1:0] i_div; +reg ce_x1, ce_x2; + +always @(posedge clk_sys) begin + reg last_hs_in; + last_hs_in <= HSync; + if(last_hs_in & !HSync) begin + i_div <= 2'b00; + end else begin + i_div <= i_div + 2'd1; + end +end + +always @(*) begin + if (!ce_divider) begin + ce_x1 = (i_div == 2'b01); + ce_x2 = i_div[0]; + end else begin + ce_x1 = i_div[0]; + ce_x2 = 1'b1; + end +end + scandoubler #(SD_HCNT_WIDTH, COLOR_DEPTH) scandoubler ( .clk_sys ( clk_sys ), .scanlines ( scanlines ), - .ce_divider ( ce_divider ), + .ce_x1 ( ce_x1 ), + .ce_x2 ( ce_x2 ), .hs_in ( HSync ), .vs_in ( VSync ), .r_in ( R ), @@ -98,10 +125,11 @@ wire [5:0] osd_r_o; wire [5:0] osd_g_o; wire [5:0] osd_b_o; -osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR) osd +osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR, OSD_AUTO_CE) osd ( .clk_sys ( clk_sys ), .rotate ( rotate ), + .ce ( scandoubler_disable ? ce_x1 : ce_x2 ), .SPI_DI ( SPI_DI ), .SPI_SCK ( SPI_SCK ), .SPI_SS3 ( SPI_SS3 ), @@ -115,25 +143,45 @@ osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR) osd .B_out ( osd_b_o ) ); +wire [5:0] cofi_r, cofi_g, cofi_b; +wire cofi_hs, cofi_vs; + +cofi cofi ( + .clk ( clk_sys ), + .pix_ce ( scandoubler_disable ? ce_x1 : ce_x2 ), + .enable ( blend ), + .hblank ( ~(scandoubler_disable ? HSync : SD_HS_O) ), + .hs ( scandoubler_disable ? HSync : SD_HS_O ), + .vs ( scandoubler_disable ? VSync : SD_VS_O ), + .red ( osd_r_o ), + .green ( osd_g_o ), + .blue ( osd_b_o ), + .hs_out ( cofi_hs ), + .vs_out ( cofi_vs ), + .red_out ( cofi_r ), + .green_out( cofi_g ), + .blue_out( cofi_b ) +); + wire [5:0] y, pb, pr; rgb2ypbpr rgb2ypbpr ( - .red ( osd_r_o ), - .green ( osd_g_o ), - .blue ( osd_b_o ), + .red ( cofi_r ), + .green ( cofi_g ), + .blue ( cofi_b ), .y ( y ), .pb ( pb ), .pr ( pr ) ); -assign VGA_R = ypbpr?pr:osd_r_o; -assign VGA_G = ypbpr? y:osd_g_o; -assign VGA_B = ypbpr?pb:osd_b_o; +assign VGA_R = ypbpr?pr:cofi_r; +assign VGA_G = ypbpr? y:cofi_g; +assign VGA_B = ypbpr?pb:cofi_b; -wire cs = scandoubler_disable ? ~(HSync ^ VSync) : ~(SD_HS_O ^ SD_VS_O); -wire hs = scandoubler_disable ? HSync : SD_HS_O; -wire vs = scandoubler_disable ? VSync : SD_VS_O; +wire cs = ~(cofi_hs ^ cofi_vs); +wire hs = cofi_hs; +wire vs = cofi_vs; // a minimig vga->scart cable expects a composite sync signal on the VGA_HS output. // and VCC on VGA_VS (to switch into rgb mode) diff --git a/common/mist/osd.v b/common/mist/osd.v index 44ecc713..7e41ed27 100644 --- a/common/mist/osd.v +++ b/common/mist/osd.v @@ -5,6 +5,7 @@ module osd ( // OSDs pixel clock, should be synchronous to cores pixel clock to // avoid jitter. input clk_sys, + input ce, // SPI interface input SPI_SCK, @@ -29,6 +30,7 @@ module osd ( parameter OSD_X_OFFSET = 10'd0; parameter OSD_Y_OFFSET = 10'd0; parameter OSD_COLOR = 3'd0; +parameter OSD_AUTO_CE = 1'b1; localparam OSD_WIDTH = 10'd256; localparam OSD_HEIGHT = 10'd128; @@ -95,7 +97,7 @@ wire [9:0] dsp_height = vs_pol ? vs_low : vs_high; wire doublescan = (dsp_height>350); -reg ce_pix; +reg auto_ce_pix; always @(posedge clk_sys) begin integer cnt = 0; integer pixsz, pixcnt; @@ -106,34 +108,35 @@ always @(posedge clk_sys) begin pixcnt <= pixcnt + 1; if(pixcnt == pixsz) pixcnt <= 0; - ce_pix <= !pixcnt; + auto_ce_pix <= !pixcnt; if(hs && ~HSync) begin cnt <= 0; if (cnt <= 512) pixsz = 0; else pixsz <= (cnt >> 9) - 1; pixcnt <= 0; - ce_pix <= 1; + auto_ce_pix <= 1; end end +wire ce_pix = OSD_AUTO_CE ? auto_ce_pix : ce; + always @(posedge clk_sys) begin - reg hsD, hsD2; - reg vsD, vsD2; + reg hsD; + reg vsD; if(ce_pix) begin // bring hsync into local clock domain hsD <= HSync; - hsD2 <= hsD; // falling edge of HSync - if(!hsD && hsD2) begin + if(!HSync && hsD) begin h_cnt <= 0; hs_high <= h_cnt; end // rising edge of HSync - else if(hsD && !hsD2) begin + else if(HSync && !hsD) begin h_cnt <= 0; hs_low <= h_cnt; v_cnt <= v_cnt + 1'd1; @@ -142,16 +145,15 @@ always @(posedge clk_sys) begin end vsD <= VSync; - vsD2 <= vsD; // falling edge of VSync - if(!vsD && vsD2) begin + if(!VSync && vsD) begin v_cnt <= 0; vs_high <= v_cnt; end // rising edge of VSync - else if(vsD && !vsD2) begin + else if(VSync && !vsD) begin v_cnt <= 0; vs_low <= v_cnt; end diff --git a/common/mist/scandoubler.v b/common/mist/scandoubler.v index 120788ca..05e9286d 100644 --- a/common/mist/scandoubler.v +++ b/common/mist/scandoubler.v @@ -25,7 +25,8 @@ module scandoubler // scanlines (00-none 01-25% 10-50% 11-75%) input [1:0] scanlines, - input ce_divider, // 0 - 4, 1 - 2 + input ce_x1, + input ce_x2, // shifter video interface input hs_in, @@ -45,34 +46,6 @@ module scandoubler parameter HCNT_WIDTH = 9; parameter COLOR_DEPTH = 6; -// try to detect changes in input signal and lock input clock gate -// it - -reg [1:0] i_div; - -reg ce_x1, ce_x2; - -always @(*) begin - if (!ce_divider) begin - ce_x1 = (i_div == 2'b01); - ce_x2 = i_div[0]; - end else begin - ce_x1 = i_div[0]; - ce_x2 = 1'b1; - end -end - -always @(posedge clk_sys) begin - reg last_hs_in; - last_hs_in <= hs_in; - if(last_hs_in & !hs_in) begin - i_div <= 2'b00; - end else begin - i_div <= i_div + 2'd1; - end -end - - // --------------------- create output signals ----------------- // latch everything once more to make it glitch free and apply scanline effect reg scanline;