VGA逐行扫描控制器的Verilog建模

前言:因为VGA是一种模拟图像传输数据接口,所要将数字信号用DAC转换成模拟量。本文用的一款ADI公司高精度的视频IC,实则一款高带宽的视频DAC。因为VGA时序较为简单,并且网上的VGA驱动基本大同小异。本文也没有什么特别创新之处。

注意点:(a)行扫描计数器和场扫描计数器需要与每个像素点、消隐数目想对应,这样才能得到正确的行列地址坐标。

参考资料:《VESA_VGA时序标准》、《ADV7123a》

源码1:逐行扫描的VGA控制器

 `timescale  ns /  ps
`define RedWidth
`define GreenWidth
`define BlueWidth
`define VGA640x480x60Hz
module vga_pscan_ctrl(
sys_clk,
sys_rst_n,
vga_red_i,
vga_green_i,
vga_blue_i,
column_addr_o,
row_addr_o,
frame_flag_o,
video_valid_o,
//vga port
vga_red,
vga_green,
vga_blue,
vga_v_sync,
vga_h_sync,
//special port
vga_sync,
vga_blank,
vga_clk
);
//macro
`ifdef VGA640x480x60Hz
`define ColumnWidth
`define RowWidth
`define H_SYNC
`define H_BACK_PORCH
`define H_VIDEO
`define H_FRONT_PORCH
`define H_TOTAL
`define H_BIAS //`H_SYNC+`H_BACK_PORCH
`define V_SYNC
`define V_BACK_PORCH
`define V_VIDEO
`define V_FRONT_PORCH
`define V_TOTAL
`define V_BIAS //V_SYNC+V_BACK_PORCH
`endif
input sys_clk;
input sys_rst_n;
input [`RedWidth-:] vga_red_i;
input [`GreenWidth-:] vga_green_i;
input [`BlueWidth-:] vga_blue_i;
output [`ColumnWidth-:] column_addr_o; //像素当前列地址
output [`RowWidth-:] row_addr_o; //像素当前行地址
output frame_flag_o; //帧结束
output video_valid_o; //数据有效
//vga port
output [`RedWidth-:] vga_red;
output [`GreenWidth-:] vga_green;
output [`BlueWidth-:] vga_blue;
output vga_v_sync;
output vga_h_sync;
//special port
output vga_blank;
output vga_sync;
output vga_clk;
//pix clk divider
reg pix_clk=;
always @ (posedge sys_clk) begin
pix_clk <= ~pix_clk;
end //horizion counter
reg [`ColumnWidth-:] h_cnt = ;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) h_cnt <= 0;
else if((pix_clk == 'b1)&&(h_cnt < `H_TOTAL-1)) h_cnt <= h_cnt + 1'd1;
else if((pix_clk == 'b1)&&(h_cnt == `H_TOTAL-1)) h_cnt <= 0;
else h_cnt <= h_cnt;
end //vertical counter
reg [`RedWidth-:] v_cnt = ;
always @ (posedge sys_clk) begin
if('b0 == sys_rst_n) v_cnt <= 0;
else if((pix_clk)&&(h_cnt == `H_TOTAL-)&&(v_cnt < `V_TOTAL-)) v_cnt <= v_cnt + 'd1;
else if((pix_clk)&&(h_cnt == `H_TOTAL-)&&(v_cnt == `V_TOTAL-)) v_cnt <= ;
else v_cnt <= v_cnt;
end //generate the sync
assign vga_h_sync = (h_cnt > `H_SYNC-)?'b1:1'b0;
assign vga_v_sync = (v_cnt > `V_SYNC-)?'b1:1'b0; //generate data valid
wire h_video_valid = ((h_cnt > `H_SYNC+`H_BACK_PORCH-)&&(h_cnt < `H_TOTAL-`H_FRONT_PORCH))?'b1:1'b0;
wire v_video_valid = ((v_cnt > `V_SYNC+`V_BACK_PORCH-)&&(v_cnt < `V_TOTAL-`V_FRONT_PORCH))?'b1:1'b0;
assign video_valid_o = (h_video_valid && v_video_valid)?'b1:1'b0;
//generate frame_flag_o
assign frame_flag_o = ((v_cnt == `V_TOTAL-)&&(h_cnt == `H_TOTAL-))?'b1:1'b0; //generate vga_blank and vga_sync and vga_clk
assign vga_clk = pix_clk;
assign vga_sync = 'b0;
assign vga_blank = vga_h_sync & vga_v_sync; //generate column_addr_o and row_addr_o
reg [`ColumnWidth-:] column_addr_o=;
reg [`RowWidth-:] row_addr_o=;
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) begin
column_addr_o <= ;
row_addr_o <= ;end
else if(video_valid_o) begin
column_addr_o <= h_cnt - `H_BIAS;
row_addr_o <= v_cnt - `V_BIAS;end
else begin
column_addr_o <= column_addr_o;
row_addr_o <= row_addr_o;end
end
//generate RGB
assign vga_red = (video_valid_o)?vga_red_i:`RedWidth'd0;
assign vga_green = (video_valid_o)?vga_green_i:`GreenWidth'd0;
assign vga_blue = (video_valid_o)?vga_blue_i:`BlueWidth'd0; endmodule

源码2:简单驱动

 `timescale  ns /  ps
`define RedWidth
`define GreenWidth
`define BlueWidth
`define Offset1
`define Offset2
module vga_driver(
sys_clk,
sys_rst_n,
sys_en,
vga_red_o,
vga_green_o,
vga_blue_o
);
input sys_clk;
input sys_rst_n;
input sys_en;
output [`RedWidth-:] vga_red_o;
output [`GreenWidth-:] vga_green_o;
output [`BlueWidth-:] vga_blue_o;
reg [`RedWidth-:] vga_red_o=;
reg [`GreenWidth-:] vga_green_o=;
reg [`BlueWidth-:] vga_blue_o=; //generate red vector
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) vga_red_o <= 0;
else if(sys_en) vga_red_o <= vga_red_o + 'd1;
else vga_red_o <= vga_red_o;
end //generate green vector
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) vga_green_o <= `Offset1;
else if(sys_en) vga_green_o <= vga_green_o + 'd1;
else vga_green_o <= vga_green_o;
end //generate blue vector
always @ (posedge sys_clk) begin
if(sys_rst_n == 'b0) vga_blue_o <= `Offset2;
else if (sys_en) vga_blue_o <= vga_blue_o + 'd1;
else vga_blue_o <= vga_blue_o;
end endmodule

源码3:VGA相关模块的顶层例化

 `timescale  ns /  ps
`define RedWidth
`define GreenWidth
`define BlueWidth
`define VGA640x480x60Hz
module vga(
sys_clk,
sys_rst_n,
//vga port
vga_red,
vga_blue,
vga_green,
vga_h_sync,
vga_v_sync,
//special port
vga_blank,
vga_sync,
vga_clk
);
`ifdef VGA640x480x60Hz
`define ColumnWidth
`define RowWidth
`endif
input sys_clk;
input sys_rst_n;
//vga port
output [`RedWidth-:] vga_red;
output [`GreenWidth-:] vga_green;
output [`BlueWidth-:] vga_blue;
output vga_v_sync;
output vga_h_sync;
//special io
output vga_blank;
output vga_sync;
output vga_clk;
//wires
wire [`RedWidth-:] vga_red_w;
wire [`GreenWidth-:] vga_green_w;
wire [`BlueWidth-:] vga_blue_w;
wire [`ColumnWidth-:] column_addr_w;
wire [`RowWidth-:] row_addr_w;
wire frame_flag_w;
wire video_valid_w;
vga_driver inst_vga_driver(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.sys_en(video_valid_w),
.vga_red_o(vga_red_w),
.vga_green_o(vga_green_w),
.vga_blue_o(vga_blue_w)
); vga_pscan_ctrl inst_vga_pscan_ctrl(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.vga_red_i(vga_red_w),
.vga_green_i(vga_green_w),
.vga_blue_i(vga_blue_w),
.column_addr_o(column_addr_w),
.row_addr_o(row_addr_w),
.frame_flag_o(frame_flag_w),
.video_valid_o(video_valid_w),
//vga port
.vga_red(vga_red),
.vga_green(vga_green),
.vga_blue(vga_blue),
.vga_v_sync(vga_v_sync),
.vga_h_sync(vga_h_sync),
//special port
.vga_sync(vga_sync),
.vga_blank(vga_blank),
.vga_clk(vga_clk)
); endmodule

仿真文件:

 `timescale  ns /  ps
`define RedWidth
`define GreenWidth
`define BlueWidth
module vga_tsb;
reg sys_clk;
reg sys_rst_n;
initial begin
sys_clk=;
sys_rst_n=;
# sys_rst_n=;
end
always begin
# sys_clk=~sys_clk;
end wire [`RedWidth-:] vga_red;
wire [`GreenWidth-:] vga_green;
wire [`BlueWidth-:] vga_blue;
wire vga_h_sync;
wire vga_v_sync;
vga inst_vga(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
//vga port
.vga_red(vga_red),
.vga_blue(vga_blue),
.vga_green(vga_green),
.vga_h_sync(vga_h_sync),
.vga_v_sync(vga_v_sync),
.vga_blank(vga_blank),
.vga_sync(vga_sync)
); endmodule

仿真脚本文件:

 vlib work
vmap work work vlog -work work vga_pscan_ctrl.v
vlog -work work vga_driver.v
vlog -work work vga.v
vlog -work work vga_tsb.v vsim -novopt -lib work vga_tsb view wave
# signals in vga_driver
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_driver/vga_red_o
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_driver/vga_green_o
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_driver/vga_blue_o
add wave sim:/vga_tsb/inst_vga/inst_vga_driver/sys_en # signals in vga_pscan_ctrl
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_red_i
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_green_i
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_blue_i
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/column_addr_o
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/row_addr_o
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/frame_flag_o
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/video_valid_o
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_sync
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_blank
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/pix_clk
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/v_video_valid
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_v_sync
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/v_cnt
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_h_sync
add wave sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/h_video_valid
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/h_cnt
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_red
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_green
add wave -radix unsigned sim:/vga_tsb/inst_vga/inst_vga_pscan_ctrl/vga_blue run 50ms
上一篇:PostgreSQL wiki


下一篇:重构改善既有代码设计--重构手法11:Move Field (搬移字段)