diff --git a/Arcade-QBert.sv b/Arcade-QBert.sv index 1b93aa2..ca4aa26 100644 --- a/Arcade-QBert.sv +++ b/Arcade-QBert.sv @@ -182,6 +182,9 @@ localparam CONF_STR = { "H0O89,Aspect ratio,Original,Full Screen,[ARC1],[ARC2];", "O5,Orientation,Vert,Horz;", "OFH,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%,CRT 75%;", + "OIL,Analog Video H-Pos,0,-1,-2,-3,-4,-5,-6,-7,8,7,6,5,4,3,2,1;", + "OMP,Analog Video V-Pos,0,-1,-2,-3,-4,-5,-6,-7,8,7,6,5,4,3,2,1;", + "OB,VFlip,Off,On;", // "OC,HFlip,Off,On;", "-;", @@ -561,10 +564,30 @@ wire no_rotate = status[5] | (mod==mod_tylz) | (mod==mod_insector) | direct_vide //wire scandoubler = (status[17:15] || forced_scandoubler); screen_rotate screen_rotate (.*); +wire hs_rs, vs_rs; +wire [3:0] hoffset = status[20:17]; +wire [3:0] voffset = status[24:21]; + +video_resync video_resync +( + .clk(clk_sys), + .pxl_cen(ce_pix), + .hs_in(HSync), + .vs_in(VSync), + .LVBL(VBlank), + .LHBL(HBlank), + .hoffset(hoffset), + .voffset(voffset), + .hs_out(hs_rs), + .vs_out(vs_rs) +); + arcade_video #(256,24,0) arcade_video ( .*, .clk_video(clk_40), + .HSync(hs_rs), + .VSync(vs_rs), .RGB_in({ rgbout[23:16], rgbout[15:8], rgbout[7:0] }) ); diff --git a/files.qip b/files.qip index fed72ce..dbad377 100644 --- a/files.qip +++ b/files.qip @@ -1,6 +1,7 @@ set_global_assignment -name VERILOG_FILE rtl/8088/eu_rom.v set_global_assignment -name CDF_FILE jtag.cdf set_global_assignment -name QIP_FILE sys/sys.qip +set_global_assignment -name VERILOG_FILE rtl/video_resync.v set_global_assignment -name VERILOG_FILE rtl/dpram.v set_global_assignment -name VERILOG_FILE rtl/ram.v set_global_assignment -name VERILOG_FILE rtl/mylstar_board.v diff --git a/releases/Arcade-QBert_20211124.rbf b/releases/Arcade-QBert_20211124.rbf new file mode 100644 index 0000000..bebc402 Binary files /dev/null and b/releases/Arcade-QBert_20211124.rbf differ diff --git a/rtl/video_resync.v b/rtl/video_resync.v new file mode 100644 index 0000000..9248932 --- /dev/null +++ b/rtl/video_resync.v @@ -0,0 +1,108 @@ +/* This file is part of JT_FRAME. + JTFRAME 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 3 of the License, or + (at your option) any later version. + + JTFRAME 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 JTFRAME. If not, see . + + Author: Jose Tejada Gomez. Twitter: @topapate + Version: 1.0 + Date: 25-9-2019 */ + +module video_resync( + input clk, + input pxl_cen, + input hs_in, + input vs_in, + input LVBL, + input LHBL, + input [3:0] hoffset, + input [3:0] voffset, + output reg hs_out, + output reg vs_out +); + +parameter CNTW = 10; // max 1024 pixels/lines + +reg [CNTW-1:0] hs_pos[0:1], vs_hpos[0:1], vs_vpos[0:1],// relative positions of the original sync pulses + hs_len[0:1], vs_len[0:1], // count the length of the original sync pulses + hs_cnt, vs_cnt, // count the position of the original sync pulses + hs_hold, vs_hold; +reg last_LHBL, last_LVBL, last_hsin, last_vsin; + +wire hb_edge, hs_edge, hs_n_edge, vb_edge, vs_edge, vs_n_edge; +reg field; + +wire [CNTW-1:0] hpos_off = { {CNTW-4{hoffset[3]}}, hoffset[3:0] }; +wire [CNTW-1:0] htrip = hs_pos[field] + hpos_off; +wire [CNTW-1:0] vs_htrip = vs_hpos[field] + hpos_off; +wire [CNTW-1:0] vs_vtrip = vs_vpos[field] + { {CNTW-4{voffset[3]}}, voffset[3:0] }; + +assign hb_edge = LHBL && !last_LHBL; +assign hs_edge = hs_in && !last_hsin; +assign hs_n_edge = !hs_in && last_hsin; +assign vb_edge = LVBL && !last_LVBL; +assign vs_edge = vs_in && !last_vsin; +assign vs_n_edge = !vs_in && last_vsin; + +always @(posedge clk) if(pxl_cen) begin + last_LHBL <= LHBL; + last_LVBL <= LVBL; + last_hsin <= hs_in; + last_vsin <= vs_in; + + hs_cnt <= hb_edge ? {CNTW{1'b0}} : hs_cnt+1'b1; + if( vb_edge ) begin + vs_cnt <= {CNTW{1'b0}}; + field <= ~field; + end else if(hb_edge) + vs_cnt <= vs_cnt+1'b1; + + // Horizontal + if( hs_edge ) hs_pos[field] <= hs_cnt; + if( hs_n_edge ) hs_len[field] <= hs_cnt - hs_pos[field]; + + if( hs_cnt == htrip ) begin + hs_out <= 1; + hs_hold <= hs_len[field] - 1'b1; + end else begin + if( |hs_hold ) hs_hold <= hs_hold - 1'b1; + if( hs_hold == 0 ) hs_out <= 0; + end + + // Vertical + if( vs_edge ) begin + vs_hpos[field] <= hs_cnt; + vs_vpos[field] <= vs_cnt; + end + if( vs_n_edge ) vs_len[field] <= vs_cnt - vs_vpos[field]; + + if( hs_cnt == vs_htrip ) begin + if( vs_cnt == vs_vtrip ) begin + vs_hold <= vs_len[field] - 1'b1; + vs_out <= 1; + end else begin + if( |vs_hold ) vs_hold <= vs_hold - 1'b1; + if( vs_hold == 0 ) vs_out <= 0; + end + end + +end + +`ifdef SIMULATION +initial begin + hs_cnt = {CNTW{1'b0}}; + vs_cnt = {CNTW{1'b0}}; + hs_out = 0; + vs_out = 0; +end +`endif + +endmodule