// 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. ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- */ // DEFINE THE VARIOUS PIPELINE DELAYS `define ZBT_PIPELINE_DELAY 2 `define ZBT_INTERFACE_DELAY 2 `define CHARACTER_DECODE_DELAY 4 // 800 X 600 @ 72Hz with a 50.000MHz pixel clock `define H_ACTIVE 800 // pixels `define H_FRONT_PORCH 56 // pixels `define H_SYNCH 120 // pixels `define H_BACK_PORCH 64 // pixels `define H_TOTAL 1040// pixels `define V_ACTIVE 600 // lines `define V_FRONT_PORCH 37 // lines `define V_SYNCH 6 // lines `define V_BACK_PORCH 23 // lines `define V_TOTAL 666 // lines // 640 X 480 @ 60Hz with a 25.175MHz pixel clock /* `define H_ACTIVE 640 // pixels `define H_FRONT_PORCH 16 // pixels `define H_SYNCH 96 // pixels `define H_BACK_PORCH 48 // pixels `define H_TOTAL 800 // pixels `define V_ACTIVE 480 // lines `define V_FRONT_PORCH 11 // lines `define V_SYNCH 2 // lines `define V_BACK_PORCH 31 // lines `define V_TOTAL 524 // lines */ 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, R0, R1, R2, R3, R4, R5, R6, R7, G0, G1, G2, G3, G4, G5, G6, G7, B0, B1, B2, B3, B4, B5, B6, B7, 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; output R0; output R1; output R2; output R3; output R4; output R5; output R6; output R7; output B0; output B1; output B2; output B3; output B4; output B5; output B6; output B7; output G0; output G1; output G2; output G3; output G4; output G5; output G6; output G7; 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; reg R0; reg R1; reg R2; reg R3; reg R4; reg R5; reg R6; reg R7; reg G0; reg G1; reg G2; reg G3; reg G4; reg G5; reg G6; reg G7; reg B0; reg B1; reg B2; reg B3; reg B4; reg B5; reg B6; reg B7; always @ (posedge pixel_clock or posedge reset) begin R0 <= 1'b1; R1 <= 1'b1; R2 <= 1'b1; R3 <= 1'b1; R4 <= 1'b1; R5 <= 1'b1; R6 <= 1'b1; R7 <= 1'b0; G0 <= 1'b1; G1 <= 1'b1; G2 <= 1'b1; G3 <= 1'b1; G4 <= 1'b1; G5 <= 1'b0; G6 <= 1'b0; G7 <= 1'b0; B0 <= 1'b1; B1 <= 1'b1; B2 <= 1'b1; B3 <= 1'b1; B4 <= 1'b1; B5 <= 1'b1; B6 <= 1'b1; B7 <= 1'b1; end 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