From cab620d896ea5cf287bcf5607d59296e8efeeeec Mon Sep 17 00:00:00 2001 From: sorgelig Date: Fri, 30 Apr 2021 22:45:37 +0800 Subject: [PATCH] Update sys. --- sys/ascal.vhd | 17 ++--- sys/osd.v | 2 +- sys/sys.qip | 1 + sys/sys_top.v | 4 +- sys/video_freezer.sv | 143 +++++++++++++++++++++++++++++++++++++++++++ sys/video_mixer.sv | 62 ++++++++++++++----- 6 files changed, 204 insertions(+), 25 deletions(-) create mode 100644 sys/video_freezer.sv diff --git a/sys/ascal.vhd b/sys/ascal.vhd index a65ccc1..2d21b35 100644 --- a/sys/ascal.vhd +++ b/sys/ascal.vhd @@ -382,8 +382,9 @@ ARCHITECTURE rtl OF ascal IS SIGNAL avl_o_vs_sync,avl_o_vs : std_logic; SIGNAL avl_fb_ena : std_logic; - FUNCTION buf_next(a,b : natural RANGE 0 TO 2) RETURN natural IS - BEGIN + FUNCTION buf_next(a,b : natural RANGE 0 TO 2; freeze : std_logic := '0') RETURN natural IS + BEGIN + IF (freeze='1') THEN RETURN a; END IF; IF (a=0 AND b=1) OR (a=1 AND b=0) THEN RETURN 2; END IF; IF (a=1 AND b=2) OR (a=2 AND b=1) THEN RETURN 0; END IF; RETURN 1; @@ -400,6 +401,7 @@ ARCHITECTURE rtl OF ascal IS ---------------------------------------------------------- -- Output SIGNAL o_run : std_logic; + SIGNAL o_freeze : std_logic; SIGNAL o_mode,o_hmode,o_vmode : unsigned(4 DOWNTO 0); SIGNAL o_format : unsigned(5 DOWNTO 0); SIGNAL o_fb_pal_dr : unsigned(23 DOWNTO 0); @@ -1729,23 +1731,24 @@ BEGIN -------------------------------------------- -- Triple buffering. -- For intelaced video, half frames are updated independently - -- Input : Toggle buffer at end of input frame + -- Input : Toggle buffer at end of input frame + o_freeze <= freeze; o_inter <=i_inter; -- o_iendframe0<=i_endframe0; -- o_iendframe02<=o_iendframe0; IF o_iendframe0='1' AND o_iendframe02='0' THEN - o_ibuf0<=buf_next(o_ibuf0,o_obuf0); + o_ibuf0<=buf_next(o_ibuf0,o_obuf0,o_freeze); o_bufup0<='1'; END IF; o_iendframe1<=i_endframe1; -- o_iendframe12<=o_iendframe1; IF o_iendframe1='1' AND o_iendframe12='0' THEN - o_ibuf1<=buf_next(o_ibuf1,o_obuf1); + o_ibuf1<=buf_next(o_ibuf1,o_obuf1,o_freeze); o_bufup1<='1'; END IF; -- Output : Change framebuffer, and image properties, at VS falling edge IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup1='1' THEN - o_obuf1<=buf_next(o_obuf1,o_ibuf1); + o_obuf1<=buf_next(o_obuf1,o_ibuf1,o_freeze); o_bufup1<='0'; o_ihsize<=i_hrsize; -- o_ivsize<=i_vrsize; -- @@ -1773,7 +1776,7 @@ BEGIN END IF; IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN - o_obuf0<=buf_next(o_obuf0,o_ibuf0); + o_obuf0<=buf_next(o_obuf0,o_ibuf0,o_freeze); o_bufup0<='0'; END IF; diff --git a/sys/osd.v b/sys/osd.v index a4fbdde..782fc81 100644 --- a/sys/osd.v +++ b/sys/osd.v @@ -72,7 +72,7 @@ always@(posedge clk_sys) begin // command 0x40: OSDCMDENABLE, OSDCMDDISABLE if(io_din[7:4] == 4) begin if(!io_din[0]) {osd_status,highres} <= 0; - else {osd_status,info} <= {~io_din[2],io_din[2]}; + else {osd_status,info} <= {~io_din[2] & ~io_din[3],io_din[2]}; bcnt <= 0; end // command 0x20: OSDCMDWRITE diff --git a/sys/sys.qip b/sys/sys.qip index eeae907..26f8474 100644 --- a/sys/sys.qip +++ b/sys/sys.qip @@ -11,6 +11,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) v set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) gamma_corr.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_mixer.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freak.sv ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freezer.sv ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_video.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) vga_out.sv ] diff --git a/sys/sys_top.v b/sys/sys_top.v index 98e6671..3b9179a 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -618,6 +618,7 @@ wire vbuf_write; wire [23:0] hdmi_data; wire hdmi_vs, hdmi_hs, hdmi_de, hdmi_vbl; +wire freeze; `ifndef MISTER_DEBUG_NOHDMI wire clk_hdmi = hdmi_clk_out; @@ -639,7 +640,7 @@ ascal ( .reset_na (~reset_req), .run (1), - .freeze (0), + .freeze (freeze), .i_clk (clk_ihdmi), .i_ce (ce_hpix), @@ -1522,6 +1523,7 @@ emu emu .HDMI_WIDTH(direct_video ? 12'd0 : hdmi_width), .HDMI_HEIGHT(direct_video ? 12'd0 : hdmi_height), + .HDMI_FREEZE(freeze), .CLK_VIDEO(clk_vid), .CE_PIXEL(ce_pix), diff --git a/sys/video_freezer.sv b/sys/video_freezer.sv new file mode 100644 index 0000000..24d2c65 --- /dev/null +++ b/sys/video_freezer.sv @@ -0,0 +1,143 @@ +// +// video freeze with sync +// (C) Alexey Melnikov +// +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +module video_freezer +( + input clk, + + output sync, + input freeze, + + input hs_in, + input vs_in, + input hbl_in, + input vbl_in, + + output hs_out, + output vs_out, + output hbl_out, + output vbl_out +); + +sync_lock #(33) vs_lock +( + .clk(clk), + .sync_in(vs_in), + .sync_out(vs_out), + .de_in(vbl_in), + .de_out(vbl_out), + .freeze(freeze) +); + +wire sync_pt; +sync_lock #(21) hs_lock +( + .clk(clk), + .sync_in(hs_in), + .sync_out(hs_out), + .de_in(hbl_in), + .de_out(hbl_out), + .freeze(freeze), + .sync_pt(sync_pt) +); + +reg sync_o; +always @(posedge clk) begin + reg old_hs, old_vs; + reg vs_sync; + + old_vs <= vs_out; + + if(~old_vs & vs_out) vs_sync <= 1; + if(sync_pt & vs_sync) begin + vs_sync <= 0; + sync_o <= ~sync_o; + end +end + +assign sync = sync_o; + +endmodule + + +module sync_lock #(parameter WIDTH) +( + input clk, + + input sync_in, + input de_in, + + output sync_out, + output de_out, + + input freeze, + output sync_pt, + output valid +); + +reg [WIDTH-1:0] f_len, s_len, de_start, de_end; +reg sync_valid; + +reg old_sync; +always @(posedge clk) old_sync <= sync_in; + +always @(posedge clk) begin + reg [WIDTH-1:0] cnti; + reg f_valid; + reg old_de; + + cnti <= cnti + 1'd1; + if(~old_sync & sync_in) begin + if(sync_valid) f_len <= cnti; + f_valid <= 1; + sync_valid <= f_valid; + cnti <= 0; + end + + if(old_sync & ~sync_in & sync_valid) s_len <= cnti; + + old_de <= de_in; + if(~old_de & de_in & sync_valid) de_start <= cnti; + if(old_de & ~de_in & sync_valid) de_end <= cnti; + + if(freeze) {f_valid, sync_valid} <= 0; +end + +reg sync_o, de_o, sync_o_pre; +always @(posedge clk) begin + reg [WIDTH-1:0] cnto; + + cnto <= cnto + 1'd1; + if(old_sync & ~sync_in & sync_valid) cnto <= s_len + 2'd2; + if(cnto == f_len) cnto <= 0; + + sync_o_pre <= (cnto == (s_len>>1)); // middle in sync + if(cnto == f_len) sync_o <= 1; + if(cnto == s_len) sync_o <= 0; + if(cnto == de_start) de_o <= 1; + if(cnto == de_end) de_o <= 0; +end + +assign sync_out = freeze ? sync_o : sync_in; +assign valid = sync_valid; +assign sync_pt = sync_o_pre; +assign de_out = freeze ? de_o : de_in; + +endmodule diff --git a/sys/video_mixer.sv b/sys/video_mixer.sv index 93b106e..87500a0 100644 --- a/sys/video_mixer.sv +++ b/sys/video_mixer.sv @@ -10,10 +10,7 @@ `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. -// +// LINE_LENGTH: Length of display line in pixels when HBlank = 0; // HALF_DEPTH: If =1 then color dept is 4 bits per component // // altera message_off 10720 @@ -47,6 +44,13 @@ module video_mixer input HBlank, input VBlank, + // Freeze engine + // HDMI: displays last frame + // VGA: black screen with HSync and VSync + output HDMI_FREEZE, + input freeze, + output freeze_sync, + // video output signals output reg [7:0] VGA_R, output reg [7:0] VGA_G, @@ -60,19 +64,45 @@ localparam DWIDTH = HALF_DEPTH ? 3 : 7; localparam DWIDTH_SD = GAMMA ? 7 : DWIDTH; localparam HALF_DEPTH_SD = GAMMA ? 0 : HALF_DEPTH; +wire frz_hs, frz_vs; +wire frz_hbl, frz_vbl; +video_freezer freezer +( + .clk(CLK_VIDEO), + .freeze(freeze), + .hs_in(HSync), + .vs_in(VSync), + .hbl_in(HBlank), + .vbl_in(VBlank), + .sync(freeze_sync), + .hs_out(frz_hs), + .vs_out(frz_vs), + .hbl_out(frz_hbl), + .vbl_out(frz_vbl) +); + +assign HDMI_FREEZE = freeze; + +reg frz; +always @(posedge CLK_VIDEO) begin + reg frz1; + + frz1 <= freeze; + frz <= frz1; +end + generate if(GAMMA && HALF_DEPTH) begin - wire [7:0] R_in = {R,R}; - wire [7:0] G_in = {G,G}; - wire [7:0] B_in = {B,B}; + wire [7:0] R_in = frz ? 8'd0 : {R,R}; + wire [7:0] G_in = frz ? 8'd0 : {G,G}; + wire [7:0] B_in = frz ? 8'd0 : {B,B}; end else begin - wire [DWIDTH:0] R_in = R; - wire [DWIDTH:0] G_in = G; - wire [DWIDTH:0] B_in = B; + wire [DWIDTH:0] R_in = frz ? 1'd0 : R; + wire [DWIDTH:0] G_in = frz ? 1'd0 : G; + wire [DWIDTH:0] B_in = frz ? 1'd0 : B; end endgenerate - wire hs_g, vs_g; wire hb_g, vb_g; wire [DWIDTH_SD:0] R_gamma, G_gamma, B_gamma; @@ -90,10 +120,10 @@ generate .gamma_wr_addr(gamma_bus[17:8]), .gamma_value(gamma_bus[7:0]), - .HSync(HSync), - .VSync(VSync), - .HBlank(HBlank), - .VBlank(VBlank), + .HSync(frz_hs), + .VSync(frz_vs), + .HBlank(frz_hbl), + .VBlank(frz_vbl), .RGB_in({R_in,G_in,B_in}), .HSync_out(hs_g), @@ -105,7 +135,7 @@ generate 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}; + assign {hs_g, vs_g, hb_g, vb_g} = {frz_hs, frz_vs, frz_hbl, frz_vbl}; end endgenerate