///////////////////////////////////////////////////////////////////// //// //// //// WISHBONE rev.B2 compliant VGA/LCD Core; Pixel Generator //// //// //// //// //// //// Author: Richard Herveille //// //// richard@asics.ws //// //// www.asics.ws //// //// //// //// Downloaded from: http://www.opencores.org/projects/vga_lcd //// //// //// ///////////////////////////////////////////////////////////////////// //// //// //// Copyright (C) 2001 Richard Herveille //// //// richard@asics.ws //// //// //// //// This source file may be used and distributed without //// //// restriction provided that this copyright statement is not //// //// removed from the file and that any derivative work contains //// //// the original copyright notice and the associated disclaimer.//// //// //// //// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// //// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// //// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// //// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// //// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// //// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// //// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// //// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// //// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// //// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// //// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// //// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// //// POSSIBILITY OF SUCH DAMAGE. //// //// //// ///////////////////////////////////////////////////////////////////// // CVS Log // // $Id: vga_pgen.v,v 1.7 2003/08/01 11:46:38 rherveille Exp $ // // $Date: 2003/08/01 11:46:38 $ // $Revision: 1.7 $ // $Author: rherveille $ // $Locker: $ // $State: Exp $ // // Change History: // $Log: vga_pgen.v,v $ // Revision 1.7 2003/08/01 11:46:38 rherveille // 1) Rewrote vga_fifo_dc. It now uses gray codes and a more elaborate anti-metastability scheme. // 2) Changed top level and pixel generator to reflect changes in the fifo. // 3) Changed a bug in vga_fifo. // 4) Changed pixel generator and wishbone master to reflect changes. // // Revision 1.6 2003/05/07 09:48:54 rherveille // Fixed some Wishbone RevB.3 related bugs. // Changed layout of the core. Blocks are located more logically now. // Started work on a dual clocked/double edge 12bit output. Commonly used by external devices like DVI transmitters. // // Revision 1.5 2002/04/05 06:24:35 rherveille // Fixed a potential reset bug in the hint & vint generation. // // Revision 1.4 2002/01/28 03:47:16 rherveille // Changed counter-library. // Changed vga-core. // Added 32bpp mode. // //synopsys translate_off `include "timescale.v" //synopsys translate_on `include "vga_defines.v" module vga_pgen ( clk_i, ctrl_ven, ctrl_HSyncL, Thsync, Thgdel, Thgate, Thlen, ctrl_VSyncL, Tvsync, Tvgdel, Tvgate, Tvlen, ctrl_CSyncL, ctrl_BlankL, eoh, eov, ctrl_dvi_odf, ctrl_cd, ctrl_pc, fb_data_fifo_rreq, fb_data_fifo_empty, fb_data_fifo_q, ImDoneFifoQ, stat_acmp, clut_req, clut_adr, clut_q, clut_ack, ctrl_cbsw, clut_switch, cursor_adr, cursor0_en, cursor0_res, cursor0_xy, cc0_adr_o, cc0_dat_i, cursor1_en, cursor1_res, cursor1_xy, cc1_adr_o, cc1_dat_i, line_fifo_wreq, line_fifo_full, line_fifo_d, line_fifo_rreq, line_fifo_q, pclk_i, `ifdef VGA_12BIT_DVI dvi_pclk_p_o, dvi_pclk_m_o, dvi_hsync_o, dvi_vsync_o, dvi_de_o, dvi_d_o, `endif pclk_o, hsync_o, vsync_o, csync_o, blank_o, r_o, g_o, b_o ); // inputs & outputs input clk_i; // master clock input ctrl_ven; // Video enable signal // horiontal timing settings input ctrl_HSyncL; // horizontal sync pulse polarization level (pos/neg) input [ 7:0] Thsync; // horizontal sync pulse width (in pixels) input [ 7:0] Thgdel; // horizontal gate delay (in pixels) input [15:0] Thgate; // horizontal gate length (number of visible pixels per line) input [15:0] Thlen; // horizontal length (number of pixels per line) // vertical timing settings input ctrl_VSyncL; // vertical sync pulse polarization level (pos/neg) input [ 7:0] Tvsync; // vertical sync pulse width (in lines) input [ 7:0] Tvgdel; // vertical gate delay (in lines) input [15:0] Tvgate; // vertical gate length (number of visible lines in frame) input [15:0] Tvlen; // vertical length (number of lines in frame) // composite signals input ctrl_CSyncL; // composite sync pulse polarization level input ctrl_BlankL; // blank signal polarization level // status outputs output eoh; // end of horizontal reg eoh; output eov; // end of vertical; reg eov; // Pixel signals input [ 1: 0] ctrl_dvi_odf; input [ 1: 0] ctrl_cd; input ctrl_pc; input [31: 0] fb_data_fifo_q; input fb_data_fifo_empty; output fb_data_fifo_rreq; input ImDoneFifoQ; output stat_acmp; // active CLUT memory page reg stat_acmp; output clut_req; output [ 8: 0] clut_adr; input [23: 0] clut_q; input clut_ack; input ctrl_cbsw; // enable clut bank switching output clut_switch; // clut memory bank-switch request: clut page switched (when enabled) input [ 8: 0] cursor_adr; // cursor data address (from wbm) input cursor0_en; // enable hardware cursor0 input cursor0_res; // cursor0 resolution input [31: 0] cursor0_xy; // (x,y) address hardware cursor0 output [ 3: 0] cc0_adr_o; // cursor0 color registers address output input [15: 0] cc0_dat_i; // cursor0 color registers data input input cursor1_en; // enable hardware cursor1 input cursor1_res; // cursor1 resolution input [31: 0] cursor1_xy; // (x,y) address hardware cursor1 output [ 3: 0] cc1_adr_o; // cursor1 color registers address output input [15: 0] cc1_dat_i; // cursor1 color registers data input input line_fifo_full; output line_fifo_wreq; output [23: 0] line_fifo_d; output line_fifo_rreq; input [23: 0] line_fifo_q; // pixel clock related outputs input pclk_i; // pixel clock in output pclk_o; // pixel clock out output hsync_o; // horizontal sync pulse output vsync_o; // vertical sync pulse output csync_o; // composite sync: Hsync OR Vsync (logical OR function) output blank_o; // blanking signal output [ 7:0] r_o, g_o, b_o; reg hsync_o, vsync_o, csync_o, blank_o; reg [7:0] r_o, g_o, b_o; `ifdef VGA_12BIT_DVI output dvi_pclk_p_o; // dvi pclk+ output dvi_pclk_m_o; // dvi pclk- output dvi_hsync_o; // dvi hsync output dvi_vsync_o; // dvi vsync output dvi_de_o; // dvi data enable output [11:0] dvi_d_o; // dvi 12bit output `endif // // variable declarations // reg nVen; // video enable signal (active low) wire eol, eof; wire ihsync, ivsync, icsync, iblank; wire pclk_ena; ////////////////////////////////// // // module body // // synchronize timing/control settings (from master-clock-domain to pixel-clock-domain) always @(posedge pclk_i) nVen <= #1 ~ctrl_ven; ////////////////////////////////// // // Pixel Clock generator // vga_clkgen clk_gen( .pclk_i ( pclk_i ), .rst_i ( nVen ), .pclk_o ( pclk_o ), .dvi_pclk_p_o ( dvi_pclk_p_o ), .dvi_pclk_m_o ( dvi_pclk_m_o ), .pclk_ena_o ( pclk_ena ) ); ////////////////////////////////// // // Timing generator // // hookup video timing generator vga_tgen vtgen( .clk(pclk_i), .clk_ena ( pclk_ena ), .rst ( nVen ), .Thsync ( Thsync ), .Thgdel ( Thgdel ), .Thgate ( Thgate ), .Thlen ( Thlen ), .Tvsync ( Tvsync ), .Tvgdel ( Tvgdel ), .Tvgate ( Tvgate ), .Tvlen ( Tvlen ), .eol ( eol ), .eof ( eof ), .gate ( gate ), .hsync ( ihsync ), .vsync ( ivsync ), .csync ( icsync ), .blank ( iblank ) ); // // from pixel-clock-domain to master-clock-domain // reg seol, seof; // synchronized end-of-line, end-of-frame reg dseol, dseof; // delayed seol, seof always @(posedge clk_i) if (~ctrl_ven) begin seol <= #1 1'b0; dseol <= #1 1'b0; seof <= #1 1'b0; dseof <= #1 1'b0; eoh <= #1 1'b0; eov <= #1 1'b0; end else begin seol <= #1 eol; dseol <= #1 seol; seof <= #1 eof; dseof <= #1 seof; eoh <= #1 seol & !dseol; eov <= #1 seof & !dseof; end `ifdef VGA_12BIT_DVI always @(posedge pclk_i) if (pclk_ena) begin hsync_o <= #1 ihsync ^ ctrl_HSyncL; vsync_o <= #1 ivsync ^ ctrl_VSyncL; csync_o <= #1 icsync ^ ctrl_CSyncL; blank_o <= #1 iblank ^ ctrl_BlankL; end `else reg hsync, vsync, csync, blank; always @(posedge pclk_i) begin hsync <= #1 ihsync ^ ctrl_HSyncL; vsync <= #1 ivsync ^ ctrl_VSyncL; csync <= #1 icsync ^ ctrl_CSyncL; blank <= #1 iblank ^ ctrl_BlankL; hsync_o <= #1 hsync; vsync_o <= #1 vsync; csync_o <= #1 csync; blank_o <= #1 blank; end `endif ////////////////////////////////// // // Pixel generator section // wire [23:0] color_proc_q; // data from color processor wire color_proc_wreq; wire [ 7:0] clut_offs; // color lookup table offset wire ImDoneFifoQ; reg dImDoneFifoQ, ddImDoneFifoQ; wire [23:0] cur1_q; wire cur1_wreq; wire [23:0] rgb_fifo_d; wire rgb_fifo_empty, rgb_fifo_full, rgb_fifo_rreq, rgb_fifo_wreq; wire sclr = ~ctrl_ven; // // hookup color processor vga_colproc color_proc ( .clk ( clk_i ), .srst ( sclr ), .vdat_buffer_di ( fb_data_fifo_q ), //data_fifo_q), .ColorDepth ( ctrl_cd ), .PseudoColor ( ctrl_pc ), .vdat_buffer_empty ( fb_data_fifo_empty ), //data_fifo_empty), .vdat_buffer_rreq ( fb_data_fifo_rreq ), //data_fifo_rreq), .rgb_fifo_full ( rgb_fifo_full ), .rgb_fifo_wreq ( color_proc_wreq ), .r ( color_proc_q[23:16] ), .g ( color_proc_q[15: 8] ), .b ( color_proc_q[ 7: 0] ), .clut_req ( clut_req ), .clut_ack ( clut_ack ), .clut_offs ( clut_offs ), .clut_q ( clut_q ) ); // // clut bank switch / cursor data delay2: Account for ColorProcessor DataBuffer delay always @(posedge clk_i) if (sclr) dImDoneFifoQ <= #1 1'b0; else if (fb_data_fifo_rreq) dImDoneFifoQ <= #1 ImDoneFifoQ; always @(posedge clk_i) if (sclr) ddImDoneFifoQ <= #1 1'b0; else ddImDoneFifoQ <= #1 dImDoneFifoQ; assign clut_switch = ddImDoneFifoQ & !dImDoneFifoQ; always @(posedge clk_i) if (sclr) stat_acmp <= #1 1'b0; else if (ctrl_cbsw) stat_acmp <= #1 stat_acmp ^ clut_switch; // select next clut when finished reading clut for current video bank (and bank switch enabled) // generate clut-address assign clut_adr = {stat_acmp, clut_offs}; // // hookup data-source-selector && hardware cursor module `ifdef VGA_HWC1 // generate Hardware Cursor1 (if enabled) wire cursor1_ld_strb; reg scursor1_en; reg scursor1_res; reg [31:0] scursor1_xy; assign cursor1_ld_strb = ddImDoneFifoQ & !dImDoneFifoQ; always @(posedge clk_i) if (sclr) scursor1_en <= #1 1'b0; else if (cursor1_ld_strb) scursor1_en <= #1 cursor1_en; always @(posedge clk_i) if (cursor1_ld_strb) scursor1_xy <= #1 cursor1_xy; always @(posedge clk_i) if (cursor1_ld_strb) scursor1_res <= #1 cursor1_res; vga_curproc hw_cursor1 ( .clk ( clk_i ), .rst_i ( sclr ), .Thgate ( Thgate ), .Tvgate ( Tvgate ), .idat ( color_proc_q ), .idat_wreq ( color_proc_wreq ), .cursor_xy ( scursor1_xy ), .cursor_res ( scursor1_res ), .cursor_en ( scursor1_en ), .cursor_wadr ( cursor_adr ), .cursor_we ( cursor1_we ), .cursor_wdat ( dat_i ), .cc_adr_o ( cc1_adr_o ), .cc_dat_i ( cc1_dat_i ), .rgb_fifo_wreq ( cur1_wreq ), .rgb ( cur1_q ) ); `ifdef VGA_HWC0 // generate additional signals for Hardware Cursor0 (if enabled) reg sddImDoneFifoQ, sdImDoneFifoQ; always @(posedge clk_i) if (cur1_wreq) begin sdImDoneFifoQ <= #1 dImDoneFifoQ; sddImDoneFifoQ <= #1 sdImDoneFifoQ; end `endif `else // Hardware Cursor1 disabled, generate pass-through signals assign cur1_wreq = color_proc_wreq; assign cur1_q = color_proc_q; assign cc1_adr_o = 4'h0; `ifdef VGA_HWC0 // generate additional signals for Hardware Cursor0 (if enabled) wire sddImDoneFifoQ, sdImDoneFifoQ; assign sdImDoneFifoQ = dImDoneFifoQ; assign sddImDoneFifoQ = ddImDoneFifoQ; `endif `endif `ifdef VGA_HWC0 // generate Hardware Cursor0 (if enabled) wire cursor0_ld_strb; reg scursor0_en; reg scursor0_res; reg [31:0] scursor0_xy; assign cursor0_ld_strb = sddImDoneFifoQ & !sdImDoneFifoQ; always @(posedge clk_i) if (sclr) scursor0_en <= #1 1'b0; else if (cursor0_ld_strb) scursor0_en <= #1 cursor0_en; always @(posedge clk_i) if (cursor0_ld_strb) scursor0_xy <= #1 cursor0_xy; always @(posedge clk_i) if (cursor0_ld_strb) scursor0_res <= #1 cursor0_res; vga_curproc hw_cursor0 ( .clk ( clk_i ), .rst_i ( sclr ), .Thgate ( Thgate ), .Tvgate ( Tvgate ), .idat ( ssel1_q ), .idat_wreq ( ssel1_wreq ), .cursor_xy ( scursor0_xy ), .cursor_en ( scursor0_en ), .cursor_res ( scursor0_res ), .cursor_wadr ( cursor_adr ), .cursor_we ( cursor0_we ), .cursor_wdat ( dat_i ), .cc_adr_o ( cc0_adr_o ), .cc_dat_i ( cc0_dat_i ), .rgb_fifo_wreq ( rgb_fifo_wreq ), .rgb ( rgb_fifo_d ) ); `else // Hardware Cursor0 disabled, generate pass-through signals assign rgb_fifo_wreq = cur1_wreq; assign rgb_fifo_d = cur1_q; assign cc0_adr_o = 4'h0; `endif // // hookup RGB buffer (temporary station between WISHBONE-clock-domain // and pixel-clock-domain) // The cursor_processor pipelines introduce a delay between the color // processor's rgb_fifo_wreq and the rgb_fifo_full signals. To compensate // for this we double the rgb_fifo. wire [4:0] rgb_fifo_nword; vga_fifo #(4, 24) rgb_fifo ( .clk ( clk_i ), .aclr ( 1'b1 ), .sclr ( sclr ), .d ( rgb_fifo_d ), .wreq ( rgb_fifo_wreq ), .q ( line_fifo_d ), .rreq ( rgb_fifo_rreq ), .empty ( rgb_fifo_empty ), .nword ( rgb_fifo_nword ), .full ( ), .aempty ( ), .afull ( ) ); assign rgb_fifo_full = rgb_fifo_nword[3]; // actually half full assign line_fifo_rreq = gate & pclk_ena; assign rgb_fifo_rreq = ~line_fifo_full & ~rgb_fifo_empty; assign line_fifo_wreq = rgb_fifo_rreq; wire [7:0] r = line_fifo_q[23:16]; wire [7:0] g = line_fifo_q[15: 8]; wire [7:0] b = line_fifo_q[ 7: 0]; always @(posedge pclk_i) if (pclk_ena) begin r_o <= #1 r; g_o <= #1 g; b_o <= #1 b; end // // DVI section // `ifdef VGA_12BIT_DVI reg [11:0] dvi_d_o; reg dvi_de_o; reg dvi_hsync_o; reg dvi_vsync_o; reg [11:0] pA, pB; reg dgate, ddgate; reg dhsync, ddhsync; reg dvsync, ddvsync; always @(posedge pclk_i) if (pclk_ena) case (ctrl_dvi_odf) // synopsys full_case parallel_case 2'b00: pA <= #1 {g[3:0], b[7:0]}; 2'b01: pA <= #1 {g[4:2], b[7:3], g[0], b[2:0]}; 2'b10: pA <= #1 {g[4:2], b[7:3], 4'h0}; 2'b11: pA <= #1 {g[5:3], b[7:3], 4'h0}; endcase always @(posedge pclk_i) if (pclk_ena) case (ctrl_dvi_odf) // synopsys full_case parallel_case 2'b00: pB <= #1 {r[7:0], g[7:4]}; 2'b01: pB <= #1 {r[7:3], g[7:5], r[2:0], g[1]}; 2'b10: pB <= #1 {r[7:3], g[7:5], 4'h0}; 2'b11: pB <= #1 {1'b0, r[7:3], g[7:6], 4'h0}; endcase always @(posedge pclk_i) if (pclk_ena) dvi_d_o <= #1 pB; else dvi_d_o <= #1 pA; always @(posedge pclk_i) if (pclk_ena) begin dgate <= #1 gate; // delay once: delayed line fifo output dhsync <= #1 ~ihsync; ddhsync <= #1 dhsync; dvsync <= #1 ~ivsync; ddvsync <= #1 dvsync; end always @(posedge pclk_i) begin dvi_de_o <= #1 dgate; dvi_hsync_o <= #1 dhsync; dvi_vsync_o <= #1 dvsync; end `endif endmodule