Really beginner question: video output
Posted: Thu Dec 23, 2021 4:05 pm
Hi all,
I cannot get my head around how video output works on MISTER. In my learning experience I try to follow the book: "Designing Video Game Hardware in Verliog".
The first chapter is to setup a screen output, as this is needed to see anything (whatever you want to display).
So it starts with two simple counters for H-Sync and V-Sync and implements it and setting up a screen with 256x240px.
The next thing is to setup a testpattern and here I struggle on how to implement this.
From the Mister Framework I get the VGA_XYZ signals I can use to write to the Framework.
But how do I set the CLK_VIDEO and what is CE_PIXEL rates ? So CE_PIXEL is a divider just of CLK_VIDEO to scale ?
I cannot figure out on how to setup the clks right.
I have implemented the SYNC parameters like that:
This is pretty much a direct implementation of the book example.
So looking at the number of lines and pixels per line and the frequency (60hz) that should give me a CLK_VIDEO of 262 scanlines * 309 pixel * 60hz = 4.857 Mhz.
I can create that clock speed with a PPL, no problem.
But that does not align with any core I have seen ... Those are all having a 24mhz CLK_VIDEO and then doing something else with it
Looking at the tutorials he is setting up a VGA chip, that receives a 25mhz clock (640x480x70hz timings).
I can see why that is working this way as standard resolution for VGA 640x400 with 70hz is requireing that frequency.
What I simply do not understand: Can I just use the 4.857Mhz frequency and do I need ce_pix at all?
So how do both play together?
What is VGA_DE? Visible Area ... why is it even needed ?
Here is the complete module
I cannot get my head around how video output works on MISTER. In my learning experience I try to follow the book: "Designing Video Game Hardware in Verliog".
The first chapter is to setup a screen output, as this is needed to see anything (whatever you want to display).
So it starts with two simple counters for H-Sync and V-Sync and implements it and setting up a screen with 256x240px.
The next thing is to setup a testpattern and here I struggle on how to implement this.
From the Mister Framework I get the VGA_XYZ signals I can use to write to the Framework.
Code: Select all
//Base video clock. Usually equals to CLK_SYS.
output CLK_VIDEO,
//Multiple resolutions are supported using different CE_PIXEL rates.
//Must be based on CLK_VIDEO
output CE_PIXEL,
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
//if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio.
output [12:0] VIDEO_ARX,
output [12:0] VIDEO_ARY,
output [7:0] VGA_R,
output [7:0] VGA_G,
output [7:0] VGA_B,
output VGA_HS,
output VGA_VS,
output VGA_DE, // = ~(VBlank | HBlank)
output VGA_F1,
output [1:0] VGA_SL,
output VGA_SCALER, // Force VGA scaler
I cannot figure out on how to setup the clks right.
I have implemented the SYNC parameters like that:
Code: Select all
'ifndef HVSYNC_GENERATOR_H
'define HVSYNC_GENERATOR_H
module hvsync_generator (input clk, input reset, output hsync, output vsync, output display_on,
output hpos[8:0], output vpos[8:0]);
//Setup screen parameters
localparam H_DISPLAY = 256; //horizontal display width
localparam H_BACK = 23; //left border (back porch)
localparam H_FRONT = 7; //right border (front porch)
localparam H_SYNC = 23; //horizontal sync width
localparam V_DISPLAY = 240; //vertical display hight
localparam V_TOP = 4 ; //vertical top border
localparam V_BOTTOM = 14; //vertical bottom border
localparam V_SYNC = 4; //vertical sync # lines
//calculate resulting parameters
localparam H_SYNC_START = H_DISPLAY + H_FRONT;
localparam H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1;
localparam H_MAX = H_DISPLAY + H_BACK + H_FRONT + H_SYNC - 1;
localparam V_SYNC_START = V_DISPLAY + V_BOTTOM;
localparam V_SYNC_END = V_DISPLAY + V_BOTTOM + V_SYNC - 1;
localparam V_MAX = V_DISPLAY + V_BOTTOM + V_TOP + V_SYNC - 1;
//horizontal position counter
always @(posedge clk)
begin
hsync <= (hpos>=H_SYNC_START && hpos<=H_SYNC_END);
if(hmaxxed)
hpos <= 0;
else
hpos <= hpos + 1;
end
wire hmaxxed = (hpos == H_MAX) || reset;
//vertical position counter
always @(posedge clk)
begin
vsync <= (vpos>=V_SYNC_START && vpos<=V_SYNC_END);
if(vmaxxed)
vpos <= 0;
else
vpos <= vpos + 1;
end
wire vmaxxed = (vpos == V_MAX) || reset;
assign display_on = (hpos<H_DISPLAY) && (vpos<V_DISPLAY)
'endif
So looking at the number of lines and pixels per line and the frequency (60hz) that should give me a CLK_VIDEO of 262 scanlines * 309 pixel * 60hz = 4.857 Mhz.
I can create that clock speed with a PPL, no problem.
But that does not align with any core I have seen ... Those are all having a 24mhz CLK_VIDEO and then doing something else with it
Looking at the tutorials he is setting up a VGA chip, that receives a 25mhz clock (640x480x70hz timings).
I can see why that is working this way as standard resolution for VGA 640x400 with 70hz is requireing that frequency.
What I simply do not understand: Can I just use the 4.857Mhz frequency and do I need ce_pix at all?
So how do both play together?
What is VGA_DE? Visible Area ... why is it even needed ?
Here is the complete module
Code: Select all
module vga (
// pixel clock
input pclk,
// VGA output
output reg hs,
output reg vs,
output [7:0] r,
output [7:0] g,
output [7:0] b,
output VGA_DE
);
// 640x400 70HZ VESA according to http://tinyvga.com/vga-timing/640x400@70Hz
parameter H = 640; // width of visible area
parameter HFP = 16; // unused time before hsync
parameter HS = 96; // width of hsync
parameter HBP = 48; // unused time after hsync
parameter V = 400; // height of visible area
parameter VFP = 12; // unused time before vsync
parameter VS = 2; // width of vsync
parameter VBP = 35; // unused time after vsync
reg[9:0] h_cnt; // horizontal pixel counter
reg[9:0] v_cnt; // vertical pixel counter
reg hblank;
reg vblank;
// both counters count from the begin of the visibla area
// horizontal pixel counter
always@(posedge pclk) begin
if(h_cnt==H+HFP+HS+HBP-1) h_cnt <= 10'b0;
else h_cnt <= h_cnt + 10'b1;
// generate negative hsync signal
if(h_cnt == H+HFP) hs <= 1'b0;
if(h_cnt == H+HFP+HS) hs <= 1'b1;
if(h_cnt == H+HFP+HS) hblank <= 1'b1; else hblank<=1'b0;
end
// veritical pixel counter
always@(posedge pclk) begin
// the vertical counter is processed at the begin of each hsync
if(h_cnt == H+HFP) begin
if(v_cnt==VS+VBP+V+VFP-1) v_cnt <= 10'b0;
else v_cnt <= v_cnt + 10'b1;
// generate positive vsync signal
if(v_cnt == V+VFP) vs <= 1'b1;
if(v_cnt == V+VFP+VS) vs <= 1'b0;
if(v_cnt == V+VFP+VS) vblank <= 1'b1; else vblank<=1'b0;
end
end
// read VRAM
reg [13:0] video_counter;
reg [7:0] pixel;
reg de;
always@(posedge pclk) begin
// The video counter is being reset at the begin of each vsync.
// Otherwise it's increased every fourth pixel in the visible area.
// At the end of the first three of four lines the counter is
// decreased by the total line length to display the same contents
// for four lines so 100 different lines are displayed on the 400
// VGA lines.
// visible area?
if((v_cnt < V) && (h_cnt < H)) begin
if(h_cnt[1:0] == 2'b11)
video_counter <= video_counter + 14'd1;
pixel <= (v_cnt[2] ^ h_cnt[2])?8'h00:8'hff; // checkboard
de<=1;
end else begin
if(h_cnt == H+HFP) begin
if(v_cnt == V+VFP)
video_counter <= 14'd0;
else if((v_cnt < V) && (v_cnt[1:0] != 2'b11))
video_counter <= video_counter - 14'd160;
de<=0;
end
pixel <= 8'h00; // black
end
end
// seperate 8 bits into three colors (332)
assign r = { pixel[7:5], 3'b00000 };
assign g = { pixel[4:2], 3'b00000 };
assign b = { pixel[1:0], 4'b000000 };
//assign VGA_DE = ~(hblank | vblank);
assign VGA_DE = de;
endmodule