Arlet wrote:
...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.
Arlet wrote:
...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:
/*
* 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:
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