// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" // SOLELY FOR USE IN DEVELOPING PROGRAMS AND SOLUTIONS FOR // XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION // AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION // OR STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS // IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, // AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE // FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY // WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE // IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR // REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF // INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // FOR A PARTICULAR PURPOSE. // // (c) Copyright 2002 Xilinx, Inc. // All rights reserved. // /* ------------------------------------------------------------------------------- Title : SVGA Video Controller Project : MicroBlaze Demo Board ------------------------------------------------------------------------------- File : SVGA_TIMING_GENERATION.v Company : Xilinx, Inc. Created : 2001/06/20 Last Update: 2001/06/20 Copyright : (c) Xilinx Inc, 2001 ------------------------------------------------------------------------------- Uses : svga_defines.v ------------------------------------------------------------------------------- Used by : SVGA_CTRL.v ------------------------------------------------------------------------------- Description: This module creates the timing and control signals for the MicroBlaze SVGA output. The module provides bit-mapped addressing in addition to the control signals for the DAC and the VGA output connector. The design supports screen resolutions up to 1024 x 768. The user will have to add the video memory and the pixel clock generation. The user has access to the video memory during the blanking intervals. The "user_access_ok" signal indicates that the user may access video memory and the "select_user_clock" signal provides a means to switch the memory clock to a user defined clock during user access. A BUFGMUX should be used to switch the clocks. The video mode used is defined in the svga_defines.v file. Conventions: All port signals are UPPER CASE. Active HIGH PORT signals have a P suffex Active LOW PORT signals have a N suffex. All internal signals are LOWER CASE and are active HIGH. ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- */ `include "svga_defines.v" module SVGA_TIMING_GENERATION ( pixel_clock, reset, h_synch_delay, v_synch_delay, comp_synch, blank, vga_ram_read_address, user_access_ok, select_user_clock, pixel_clk_out); input pixel_clock; // pixel clock input reset; // reset output h_synch_delay; // horizontal synch for VGA connector output v_synch_delay; // vertical synch for VGA connector output comp_synch; // composite synch for DAC output blank; // composite blanking output [19:0]vga_ram_read_address; // bit mapped mode address output user_access_ok; // flag to indicate that the video memory may be accessed by the user output select_user_clock; // flag to select the memory clock either the pixel_clock or the user clock //added RGB signals here RL output pixel_clk_out; reg [9:0] line_count; // counts the display lines reg [10:0] pixel_count; // counts the pixels in a line reg h_synch; // horizontal synch reg v_synch; // vertical synch reg h_synch_delay; // h_synch delayed 2 clocks to line up with DAC pipeline reg v_synch_delay; // v_synch delayed 2 clocks to line up with DAC pipeline reg h_synch_delay0; // h_synch delayed 1 clock reg v_synch_delay0; // v_synch delayed 1 clock reg h_c_synch; // horizontal component of comp synch reg v_c_synch; // vertical component of comp synch reg comp_synch; // composite synch for DAC reg h_blank; // horizontal blanking reg v_blank; // vertical blanking reg blank; // composite blanking reg [19:0] vga_ram_read_address; // address of the video pixel in memory reg reset_vga_ram_read_address;// flag to reset the ram address during VBI reg hold_vga_ram_read_address;// flag to hold the address during HBI reg user_access_ok; reg user_access_vbi; reg user_access_hbi; reg user_clock_hbi; reg user_clock_vbi; reg select_user_clock; wire pixel_clk_out; assign pixel_clk_out = pixel_clock; // CREATE THE HORIZONTAL LINE PIXEL COUNTER always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset set pixel counter to 0 pixel_count <= 11'h000; end else if (pixel_count == (`H_TOTAL - 1)) begin // last pixel in the line pixel_count <= 11'h000; // reset pixel counter end else begin pixel_count <= pixel_count +1; end end // CREATE THE HORIZONTAL SYNCH PULSE always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset h_synch <= 1'b0; // remove h_synch end else if (pixel_count == (`H_ACTIVE + `H_FRONT_PORCH -1)) begin // start of h_synch h_synch <= 1'b1; end else if (pixel_count == (`H_TOTAL - `H_BACK_PORCH -1)) begin // end of h_synch h_synch <= 1'b0; end end // CREATE THE VERTICAL FRAME LINE COUNTER always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset set line counter to 0 line_count <= 10'h000; end else if ((line_count == (`V_TOTAL - 1))&& (pixel_count == (`H_TOTAL - 1))) begin // last pixel in last line of frame line_count <= 10'h000; // reset line counter end else if ((pixel_count == (`H_TOTAL - 1))) begin // last pixel but not last line line_count <= line_count + 1; // increment line counter end end // CREATE THE VERTICAL SYNCH PULSE always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset v_synch = 1'b0; // remove v_synch end else if ((line_count == (`V_ACTIVE + `V_FRONT_PORCH -1) && (pixel_count == `H_TOTAL - 1))) begin // start of v_synch v_synch = 1'b1; end else if ((line_count == (`V_TOTAL - `V_BACK_PORCH - 1)) && (pixel_count == (`H_TOTAL - 1))) begin // end of v_synch v_synch = 1'b0; end end // ADD TWO PIPELINE DELAYS TO THE SYNCHs COMPENSATE FOR THE DAC PIPELINE DELAY always @ (posedge pixel_clock or posedge reset) begin if (reset) begin h_synch_delay0 <= 1'b0; v_synch_delay0 <= 1'b0; h_synch_delay <= 1'b0; v_synch_delay <= 1'b0; end else begin h_synch_delay0 <= h_synch; v_synch_delay0 <= v_synch; h_synch_delay <= h_synch_delay0; v_synch_delay <= v_synch_delay0; end end // CREATE THE HORIZONTAL BLANKING SIGNAL // the "-2" is used instead of "-1" because of the extra register delay // for the composite blanking signal always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset h_blank <= 1'b0; // remove the h_blank end else if (pixel_count == (`H_ACTIVE -2)) begin // start of HBI h_blank <= 1'b1; //h_blank <= 1'b0; end else if (pixel_count == (`H_TOTAL -2)) begin // end of HBI h_blank <= 1'b0; //h_blank <= 1'b1; end end // CREATE THE VERTICAL BLANKING SIGNAL // the "-2" is used instead of "-1" in the horizontal factor because of the extra // register delay for the composite blanking signal always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset v_blank <= 1'b0; // remove v_blank end else if ((line_count == (`V_ACTIVE - 1) && (pixel_count == `H_TOTAL - 2))) begin // start of VBI v_blank <= 1'b1; // v_blank <= 1'b0; end else if ((line_count == (`V_TOTAL - 1)) && (pixel_count == (`H_TOTAL - 2))) begin // end of VBI v_blank <= 1'b0; // v_blank <= 1'b1; end end // CREATE THE COMPOSITE BLANKING SIGNAL always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset //blank <= 1'b0; // remove blank blank <= 1'b1; end else if (h_blank || v_blank) // blank during HBI or VBI begin //blank <= 1'b1; blank <= 1'b0; end else begin //blank <= 1'b0; // active video do not blank blank <= 1'b1; // active video do not blank end end // CREATE THE HORIZONTAL COMPONENT OF COMP SYNCH // the "-2" is used instead of "-1" because of the extra register delay // for the composite synch always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset //h_c_synch <= 1'b0; // remove h_c_synch h_c_synch <= 1'b1; // remove h_c_synch end else if (pixel_count == (`H_ACTIVE + `H_FRONT_PORCH -2)) begin // start of h_c_synch //h_c_synch <= 1'b1; h_c_synch <= 1'b0; end else if (pixel_count == (`H_TOTAL - `H_BACK_PORCH -2)) begin // end of h_c_synch //h_c_synch <= 1'b0; h_c_synch <= 1'b1; end end // CREATE THE VERTICAL COMPONENT OF COMP SYNCH always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset v_c_synch <= 1'b0; // remove v_c_synch //v_c_synch <= 1'b1; end else if ((line_count == (`V_ACTIVE + `V_FRONT_PORCH - 1) && (pixel_count == `H_TOTAL - 2))) begin // start of v_c_synch v_c_synch <= 1'b1; //v_c_synch <= 1'b0; end else if ((line_count == (`V_TOTAL - `V_BACK_PORCH - 1)) && (pixel_count == (`H_TOTAL - 2))) begin // end of v_c_synch v_c_synch <= 1'b0; //v_c_synch <= 1'b1; end end // CREATE THE COMPOSITE SYNCH SIGNAL always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset comp_synch <= 1'b0; // remove comp_synch //comp_synch <= 1'b1; end else begin comp_synch <= (v_c_synch ^ h_c_synch); //comp_synch <= (v_c_synch || h_c_synch); end end // CREATE THE RAM ADDRESS COUNTER always @ (posedge pixel_clock or posedge reset) begin if (reset) begin vga_ram_read_address <= 20'h00000; end else if (reset_vga_ram_read_address) begin vga_ram_read_address <= 20'h00000; end else if (!hold_vga_ram_read_address) begin vga_ram_read_address <= vga_ram_read_address + 1; end end // CREATE THE CONTROL SIGNALS FOR THE VGA RAM ADDRESS COUNTER always @ (posedge pixel_clock or posedge reset) begin if (reset) begin reset_vga_ram_read_address <= 1'b0; end else if ((line_count == `V_ACTIVE -1) &&(pixel_count ==((`H_TOTAL -1) -(`ZBT_PIPELINE_DELAY + `ZBT_INTERFACE_DELAY)))) begin reset_vga_ram_read_address <= 1'b1; // reset the address counter at the end of active video end else if ((line_count == `V_TOTAL -1) &&(pixel_count ==((`H_TOTAL -1) -(`ZBT_PIPELINE_DELAY + `ZBT_INTERFACE_DELAY)))) begin reset_vga_ram_read_address <= 1'b0; // re-enable the address counter at the start of active video end end always @ (posedge pixel_clock or posedge reset) begin if (reset) begin hold_vga_ram_read_address <= 1'b0; end else if (pixel_count == ((`H_ACTIVE-1)- (`ZBT_PIPELINE_DELAY + `ZBT_INTERFACE_DELAY))) begin // hold the address counter at the end of active video hold_vga_ram_read_address <= 1'b1; end else if (pixel_count == ((`H_TOTAL -1) -(`ZBT_PIPELINE_DELAY + `ZBT_INTERFACE_DELAY))) begin // re-enable the address counter at the start of active video hold_vga_ram_read_address <= 1'b0; end end // CREATE THE FLAG TO INDICATE THAT THE VIDEO MEMORY MAY BE ACCESSED BY THE USER // The flag is removed 5 times the ZBT startup to allow the clocks to be switched // and allow the SVGA controller to apply the next address always @ (posedge pixel_clock or posedge reset) begin if (reset) begin user_access_hbi <= 1'b0; end else if (pixel_count == `H_ACTIVE +16) begin user_access_hbi <= 1'b1; end else if (pixel_count == ((`H_TOTAL -1) - (5*(`ZBT_PIPELINE_DELAY + `ZBT_INTERFACE_DELAY)))) begin user_access_hbi <= 1'b0; end end always @ (posedge pixel_clock or posedge reset) begin if (reset) begin user_access_vbi <= 1'b0; end else if ((line_count == `V_ACTIVE) && (pixel_count == `H_ACTIVE +16)) begin user_access_vbi <= 1'b1; end else if ((line_count == `V_TOTAL -1) && (pixel_count ==(`H_TOTAL -1) - (5*(`ZBT_PIPELINE_DELAY + `ZBT_INTERFACE_DELAY)))) begin user_access_vbi <= 1'b0; end end always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset user_access_ok <= 1'b0; // remove user access end else if (user_access_hbi || user_access_vbi) // allow access during HBI or VBI begin user_access_ok <= 1'b1; end else begin user_access_ok <= 1'b0; // svga controller is accessing memory end end // CREATE THE FLAG TO SELECT A USER CLOCK FOR MEMORY ACCESS DURING BLANKING always @ (posedge pixel_clock or posedge reset) begin if (reset) begin user_clock_hbi <= 1'b0; end else if (pixel_count == `H_ACTIVE +8) begin user_clock_hbi <= 1'b1; end else if (pixel_count == ((`H_TOTAL -1) - (3*(`ZBT_PIPELINE_DELAY + `ZBT_INTERFACE_DELAY)))) begin user_clock_hbi <= 1'b0; end end always @ (posedge pixel_clock or posedge reset) begin if (reset) begin user_clock_vbi <= 1'b0; end else if ((line_count == `V_ACTIVE) && (pixel_count == `H_ACTIVE +8 )) begin user_clock_vbi <= 1'b1; end else if ((line_count == `V_TOTAL -1) && (pixel_count ==(`H_TOTAL -1) - (3*(`ZBT_PIPELINE_DELAY + `ZBT_INTERFACE_DELAY)))) begin user_clock_vbi <= 1'b0; end end always @ (posedge pixel_clock or posedge reset) begin if (reset) begin // on reset select_user_clock <= 1'b0; // startup with pixel clock end else if (user_clock_hbi || user_clock_vbi) // switch to user clock during HBI or VBI begin select_user_clock <= 1'b1; end else begin select_user_clock <= 1'b0; // switch back to pixel clock end end endmodule //SVGA_TIMING_GENERATION