...The delay is not a problem. There's 15 ns delay in a 10-foot VGA cable, and you don't notice that, do you ?...
That is not a problem since the delay is after the output. But I am thinking ahead to when there's a cpu writing and reading from the RAM. Surely the delay is a concern here, which is why I add an estimated delay of the FPGA to the RAM delay to get an idea of the overall top speed.
...it would be easier to use the main clock directly as the pixel clock...
I am having a problem trying to do this. It is giving me a nasty little message "This design may not be routable!..." I am using a DCM to get the 108MHz from 100MHz. It has 4 108MHz outputs. 1 goes to your HVSYNC(vga.v) module, 1 goes to the SDRAMif module, 1 goes offchip to the SyncRAM clk, and 1 goes to the videoDAC clk. The 108MHz has been verified by 'scope. Here are the 2 modules:
Code: Select all
/*
* vga.v
*
* VGA timing generator
*
* This module only generates the VGA sync signals and control signals
* for the actual video generator. Add a suitable video generator to
* create real outputs.
*
* +-------+ +-----------------+
* | vga.v | ----> | video generator | ----> RGB outputs
* +---+---+ +-----------------+
* |
* `-----------------------------------> Hsync/Vsync ouputs
*
* The hstart/vstart and blank signals are short enable pulses with a
* width equal to the pixel clock (pclk). They are intended to drive
* a state machine in the video generator. All outputs are fully
* registered. The 'hstart' pulse signals that next pclk will shift out
* the leftmost pixel of each line. The 'hblank' pulse signals that the
* next pclk must be blanked. Likewise, the 'vstart' and 'vblank' enables
* do the same thing for vertical blanking, but with less precise timing.
*
* So, use the vstart/vblank to update state machine, and use hstart/hblank
* for pixel timing.
*
* The hsync/vsync signals are delayed by 1 pclk period with
* respect to the vstart/hstart/blank signals. It is intended that
* the video generator will introduce a 1 pclk pipeline delay so that
* the signals will align again. If the video generator requires a
* larger delay, the hsync and vsync signals need to be delayed as well.
*
* The design has been optimised for speed (>200 MHz on Spartan-3
* with ISE 9.2 and one-hot FSM encoding selected).
*
* (C) Arlet Ottens, <arlet@c-scape.nl>
*/
module vga( input pclk,
//output reg pclk = 0, // pixel clock
output reg hsync, // horizontal sync
output reg vsync, // vertical sync
output reg hstart, // line start on next clock
output reg vstart, // field starts on next clock
output reg hblank = 1, // hblank on next clock
output reg vblank = 0 // vblank on next clock
);
// timing parameters
parameter
HFRONT = 10'd48, // front porch (+right border)
HVIDEO = 10'd1280, // active video area
HSYNC = 10'd112, // hsync
HBACK = 10'd248; // back porch (+left border)
parameter
VFRONT = 10'd3, // front porch (+bottom border)
VVIDEO = 10'd1024, // active vide area
VSYNC = 10'd3, // vsync
VBACK = 10'd38; // back porch (+top border)
// states (used for both H and V state machines)
parameter
VIDEO = 2'd0,
FRONT = 2'd1,
SYNC = 2'd2,
BACK = 2'd3;
// horizontal counters and state
reg [11:0] hcount = 0; // down counter for horizontal state
reg [10:0] hload; // next load value
reg [1:0] hstate = FRONT; // horizontal state
wire hcount_done = hcount[11]; // done when count < 0
// vertical counters and state
reg [11:0] vcount = 0; // down counter for vertical state
reg [10:0] vload; // next load value
reg [1:0] vstate = FRONT; // horizontal state
wire vcount_done = vcount[11]; // done when count < 0
// enable signal for V state machine
wire venable = (hstate == FRONT) & hcount_done & pclk;
// make 25 MHz pixel clock from 50MHz input clock
//always @(posedge clk50)
//pclk <= ~pclk;
// preload next timer value depending on state
// subtract 2 from timing value to compensate for pipeline delays
// This should be synthesized as a small LUT ROM, so it's quite
// efficient.
always @(posedge pclk)
hload <= (hstate == BACK) ? HVIDEO - 2:
(hstate == VIDEO) ? HFRONT - 2:
(hstate == FRONT) ? HSYNC - 2:
HBACK - 2;
// do the same for vertical
always @(posedge pclk)
vload <= (vstate == BACK) ? VVIDEO - 2:
(vstate == VIDEO) ? VFRONT - 2:
(vstate == FRONT) ? VSYNC - 2:
VBACK - 2;
// adjust down counter. Reload when it's done.
always @(posedge pclk)
//if( pclk ) begin
if( hcount_done )
hcount <= { 1'b0, hload };
else
hcount <= hcount - 1;
//end
// when down counter is done, go to next state
always @(posedge pclk)
if( hcount_done )
case( hstate )
VIDEO : hstate <= FRONT;
FRONT : hstate <= SYNC;
SYNC : hstate <= BACK;
BACK : hstate <= VIDEO;
endcase
// start of active line
always @(posedge pclk)
//if( pclk )
hstart <= (hstate == BACK) & hcount_done & ~vblank;
// vstart pulse to signal end of vertical blanking
always @(posedge pclk)
//if( pclk )
vstart <= (vstate == BACK) & venable & vcount_done;
// adjust down counter. Reload when it's done.
always @(posedge pclk)
if( venable ) begin
if( vcount_done )
vcount <= { 1'b0, vload };
else
vcount <= vcount - 1;
end
// when down counter is done, go to next state
always @(posedge pclk)
if( venable & vcount_done )
case( vstate )
VIDEO : vstate <= FRONT;
FRONT : vstate <= SYNC;
SYNC : vstate <= BACK;
BACK : vstate <= VIDEO;
endcase
// update registered outputs
always @(posedge pclk) begin
//if( pclk ) begin
hsync <= hstate == SYNC;
vsync <= vstate == SYNC;
hblank <= (vstate == VIDEO) & (hstate == VIDEO) & hcount_done;
vblank <= vstate != VIDEO;
//end
end
endmodule
Code: Select all
module SRAMif( output reg [20:0] SRAddr = 0,
output reg WEn = 1,
output reg SRCS = 1,
input [15:0] SRD,
output reg [4:0] Red_data,
output reg [5:0] Green_data,
output reg [4:0] Blue_data,
output reg DACBLANKn = 1,
//input clk50,
input pclk,
input hstart,
input vstart,
input hblank
);
reg [15:0] SRDtemp;
reg countflag;
always @(posedge pclk)
//if ( pclk )
if ( hstart )
countflag <= 1; //countflag active in display area
else if ( hblank )
countflag <= 0;
always @(posedge pclk)
if ( vstart ) //reset address counter at top left of screen
SRAddr <= 0;
else if ( countflag )
SRAddr <= SRAddr + 1; //increment RAM address counter
always @(posedge pclk)
if ( countflag )
begin
SRDtemp <= SRD; //latch incoming data
Red_data <= hblank ? 0 : SRDtemp [15:11]; //outgoing data to videoDAC
Green_data <= hblank ? 0 : SRDtemp [10:5];
Blue_data <= hblank ? 0 : SRDtemp [4:0];
end
endmodule