VGA控制器的编写主要是了解VGA的显示标准和时序,如1024X768@60Hz,确定时钟频率(65MHz=1344X806X60),列像素时间等于时钟周期,扫描从左到右、从上到下(类似于电视扫描PAL)。除有效时间外,一行还有同步脉冲时间、后肩和前肩。(http://tinyvga.com/vgatiming,http://wenku.baidu.com/view/13b3140102020740be1e9b94.html,
http://www.cnblogs.com/qiweiwang/archive/2011/01/17/1937688.html)
然后根据时序实现显示标准的功能模块,完成同步信号的输出、有效区域标志和当前坐标。一行列像素计数完成后,行计数器加1,列像素计数器清零后继续计数,知道最后一行计数完成后,行计数器清零,重复上述过程。

1 `timescale 1 ps/1 ps 2 module sync_module( 3 output VSYNC_Sig,HSYNC_Sig,Ready_Sig,Frame_Sig, 4 output [10:0]Column_Addr_Sig,Row_Addr_Sig, 5 input CLK,RSTn 6 ); 7 //VGA format: 640 X 480 @ 60Hz,pix 0.039683us≈40ns,25MHz 8 //场扫描时序: 2--30--484-- 9, 525 9 //一般: 2--33--480-- 10 10 //行扫描时序:96--45--646--13, 800 11 //一般: 96--48--640--16 12 13 //VGA format: 1024 X 768 @ 60Hz,pix 1/65MHz 14 //场扫描时序: 6-- 29-- 768-- 3, 806 15 //行扫描时序:136--160--1024--24, 1344 16 /********************************/ 17 18 reg [10:0]Count_H; 19 20 always @ ( posedge CLK or negedge RSTn ) 21 if( !RSTn ) 22 Count_H <= 11'd0; 23 else if( Count_H == 11'd1343 ) 24 Count_H <= 11'd0; 25 else 26 Count_H <= Count_H + 1'b1; 27 28 /********************************/ 29 30 reg [10:0]Count_V; 31 32 always @ ( posedge CLK or negedge RSTn ) 33 if( !RSTn ) 34 Count_V <= 11'd0; 35 else if( Count_V == 11'd805 ) 36 Count_V <= 11'd0; 37 else if( Count_H == 11'd1343 ) 38 Count_V <= Count_V + 1'b1; 39 40 /********************************/ 41 wire isReady; 42 43 assign isReady = ( ( Count_H >= 11'd296 && Count_H <= 11'd1319 ) && //有效时间1024 44 ( Count_V >= 11'd35 && Count_V <= 11'd802 ) ) ? 1'b1 : 1'b0; //768 45 46 /*********************************/ 47 48 assign VSYNC_Sig = ( Count_V < 11'd6 ) ? 1'b0 : 1'b1; //场同步信号 49 assign HSYNC_Sig = ( Count_H < 11'd136 ) ? 1'b0 : 1'b1; //行同步信号 50 assign Ready_Sig = isReady; 51 assign Frame_Sig = ( Count_V == 11'd805 ) ? 1'b1 : 1'b0; //帧结束标志 52 53 /********************************/ 54 55 assign Column_Addr_Sig = isReady ? Count_H - 11'd296 : 11'd0; // Count from 0; 列地址 56 assign Row_Addr_Sig = isReady ? Count_V - 11'd35 : 11'd0; // Count from 0; 行地址 57 58 /********************************/ 59 60 endmodule
第二个模块根据有效区域标志和当前坐标完成图像的显示,输出需要的RGB值,相对简单。

1 `timescale 1 ps/1 ps 2 module vga_control_module( 3 output Red_Sig,Green_Sig,Blue_Sig, 4 output[6:0]Rom_Addr, 5 input[15:0]Rom_Data, 6 input [10:0]Column_Addr_Sig,Row_Addr_Sig, 7 input Ready_Sig,Frame_Sig,CLK,RSTn 8 ); 9 10 /**********************************/ 11 //greenman 16X16,6pics 12 //16X96,reg [15:0] mem [6:0],帧偏移量16 13 14 reg [3:0]m; 15 wire[10:0]row_addr; 16 wire row_valid; 17 assign row_addr = Row_Addr_Sig - 11'd300; //图片显示起始位置y坐标:300 18 assign row_valid = row_addr < 16 && row_addr >= 0; //图片行有效0-15 19 20 always @ ( posedge CLK or negedge RSTn ) 21 if( !RSTn ) 22 m <= 4'd0; 23 else if( Ready_Sig && row_valid ) 24 m <= row_addr[3:0]; 25 else 26 m <= 4'd0; 27 28 /************************************/ 29 30 reg [3:0]n; 31 wire[10:0]col_addr; 32 wire col_valid; 33 assign col_addr = Column_Addr_Sig - 11'd500; //图片显示起始位置x坐标:500 34 assign col_valid = col_addr < 16 && col_addr >= 0; //图片列有效0-15 35 36 always @ ( posedge CLK or negedge RSTn ) 37 if( !RSTn ) 38 n <= 4'd0; 39 else if( Ready_Sig && col_valid ) 40 n <= col_addr[3:0]; 41 else 42 n <= 4'd0; 43 44 /**********************************/ 45 46 parameter FRAME = 10'd10; //每幅图像显示10帧 X 6 = 60Hz 47 48 /**********************************/ 49 50 reg [9:0]Count_Frame; 51 52 always @ ( posedge CLK or negedge RSTn ) 53 if( !RSTn ) 54 Count_Frame <= 10'd0; 55 else if( Count_Frame == FRAME ) 56 Count_Frame <= 10'd0; 57 else if( Frame_Sig ) 58 Count_Frame <= Count_Frame + 1'b1; //帧计数 59 60 /************************************/ 61 ///// 帧偏移地址16,状态机控制,跳转条件计数到10帧切换下一幅图像 62 63 reg [6:0]rAddr; 64 reg [3:0]state; 65 66 always @ ( posedge CLK or negedge RSTn ) 67 if( !RSTn ) 68 begin 69 rAddr <= 7'd0; 70 state <= 4'd0; 71 end 72 else 73 case ( state ) 74 75 4'd0 : 76 if( Count_Frame == FRAME ) state <= 4'd1; 77 else rAddr <= 7'd0; 78 79 4'd1 : 80 if( Count_Frame == FRAME ) state <= 4'd2; 81 else rAddr <= 7'd16; 82 83 4'd2 : 84 if( Count_Frame == FRAME ) state <= 4'd3; 85 else rAddr <= 7'd32; 86 87 4'd3 : 88 if( Count_Frame == FRAME ) state <= 4'd4; 89 else rAddr <= 7'd48; 90 91 4'd4 : 92 if( Count_Frame == FRAME ) state <= 4'd5; 93 else rAddr <= 7'd48; 94 95 4'd5 : 96 if( Count_Frame == FRAME ) state <= 4'd6; 97 else rAddr <= 7'd64; 98 99 4'd6 : 100 if( Count_Frame == FRAME ) state <= 4'd0; 101 else rAddr <= 7'd80; 102 103 endcase 104 105 /************************************/ 106 107 assign Rom_Addr = rAddr + m; //图像起始地址 + 行寻址 108 109 assign Red_Sig = Ready_Sig ? Rom_Data[ 5'd15 - n ] : 1'b0; //扫描到图片大小区域时获取ROM数据, 110 assign Green_Sig = Ready_Sig ? Rom_Data[ 5'd15 - n ] : 1'b0; //row_valid && col_valid 111 assign Blue_Sig = Ready_Sig ? ~Rom_Data[ 5'd15 - n ] : 1'b0; //不在图片区域内时显示底色:蓝色 112 113 /***********************************/ 114 115 // /**********************************/ 116 // 117 // reg [5:0]m; 118 // wire[10:0]row_add; 119 // assign row_add = Row_Addr_Sig - 11'd300; 120 // 121 // always @ ( posedge CLK or negedge RSTn ) 122 // if( !RSTn ) 123 // m <= 6'd0; 124 // else if( Ready_Sig && row_add < 64 && row_add >= 0 ) 125 // m <= row_add[5:0]; 126 // else 127 // m <= 6'd0; 128 // 129 // /************************************/ 130 // 131 // reg [5:0]n; 132 // wire[10:0]col_add; 133 // assign col_add = Column_Addr_Sig - 11'd500; 134 // 135 // always @ ( posedge CLK or negedge RSTn ) 136 // if( !RSTn ) 137 // n <= 6'd0; 138 // else if( Ready_Sig && col_add < 64 && col_add >= 0 ) 139 // n <= col_add[5:0]; 140 // else 141 // n <= 6'd0; 142 // 143 // /************************************/ 144 // 145 // assign Rom_Addr = m; 146 // 147 // assign Red_Sig = Ready_Sig ? Red_Rom_Data[ 6'd63 - n ] : 1'b0; //3个ROM读取不同的RGB值 148 // assign Green_Sig = Ready_Sig ? Green_Rom_Data[ 6'd63 - n ] : 1'b0; 149 // assign Blue_Sig = Ready_Sig ? Blue_Rom_Data[ 6'd63 - n ] : 1'b0; 150 151 152 ////---------显示一个圆-------------------- 153 //parameter radius = 11'd100; //半径 154 //parameter radius2 = radius * radius; //半径的平方 155 //parameter x_pos = 11'd400; //圆心x坐标 156 //parameter y_pos = 11'd500; //圆心y坐标 157 // 158 //reg[10:0] x_temp,y_temp; 159 //reg[21:0] x_temp_2,y_temp_2; 160 //wire is_flag; 161 // 162 //always@* 163 // if(Column_Addr_Sig >= x_pos) 164 // x_temp = Column_Addr_Sig - x_pos; 165 // else 166 // x_temp = x_pos - Column_Addr_Sig; 167 // 168 //always@* 169 // if(Row_Addr_Sig >= y_pos) 170 // y_temp = Row_Addr_Sig - y_pos; 171 // else 172 // y_temp = y_pos - Row_Addr_Sig; 173 // 174 //always@* 175 // x_temp_2 = x_temp * x_temp; 176 // 177 //always@* 178 // y_temp_2 = y_temp * y_temp; 179 // 180 //assign is_flag = (x_temp_2 + y_temp_2) <= 10000; 181 // 182 //assign Red_Sig = Ready_Sig ? is_flag : 1'b0; 183 //assign Green_Sig = Ready_Sig ? ~is_flag : 1'b0; 184 //assign Blue_Sig = Ready_Sig ? ~is_flag : 1'b0; 185 186 //-------------------------------------------------- 187 //显示一个矩形框 188 //wire a_dis,b_dis,c_dis,d_dis; //矩形框显示区域定位 189 // 190 //assign a_dis = ( (Column_Addr_Sig>=200) && (Column_Addr_Sig<220) ) 191 // && ( (Row_Addr_Sig>=140) && (Row_Addr_Sig<460) ); 192 // 193 //assign b_dis = ( (Column_Addr_Sig>=580) && (Column_Addr_Sig<600) ) 194 // && ( (Row_Addr_Sig>=140) && (Row_Addr_Sig<460) ); 195 // 196 //assign c_dis = ( (Column_Addr_Sig>=220) && (Column_Addr_Sig<580) ) 197 // && ( (Row_Addr_Sig>=140) && (Row_Addr_Sig<160) ); 198 // 199 //assign d_dis = ( (Column_Addr_Sig>=220) && (Column_Addr_Sig<580) ) 200 // && ( (Row_Addr_Sig>=440) && (Row_Addr_Sig<460) ); 201 // 202 // //显示一个小矩形 203 //wire e_rdy; //矩形的显示有效矩形区域 204 // 205 //assign e_rdy = ( (Column_Addr_Sig>=385) && (Column_Addr_Sig<=415) ) 206 // && ( (Row_Addr_Sig>=285) && (Row_Addr_Sig<=315) ); 207 // 208 ////-------------------------------------------------- 209 // //r,g,b控制液晶屏颜色显示,背景显示蓝色,矩形框显示红蓝色 210 //assign Red_Sig = Ready_Sig ? e_rdy : 1'b0; 211 //assign Green_Sig = Ready_Sig ? (a_dis | b_dis | c_dis | d_dis) : 1'b0; 212 //assign Blue_Sig = Ready_Sig ? ~(a_dis | b_dis | c_dis | d_dis) : 1'b0; 213 214 //wire a_pos; 215 //assign a_pos = Column_Addr_Sig > 11'd0 && Row_Addr_Sig < 11'd100 ; 216 //// /************************************/ 217 //// 218 // assign Red_Sig = Ready_Sig ? a_pos: 1'b0; 219 // assign Green_Sig = Ready_Sig ? a_pos : 1'b0; 220 // assign Blue_Sig = Ready_Sig ? ~a_pos : 1'b0; 221 222 endmodule