📄 0923freedev_vga.v
字号:
//---------------------------------------------------------------
//模块名称:freedev_vga
//功能说明:VGA显示模块
// 1、通过slave port设置模块工作参数
// 2、avalon master bust方式读内存显示缓冲区
//
//日 期:20070917
//备 注:
// 1、Avalone总线Slave设备
// 2、Avalon总线Master设备 burst传输
// 数字图象处理板EP2C35F672C6支持以下分辨率(后为象素频率)
// 3、1024*768*60 65M
// 4、800*600*60 40M
// 5、640*480*60 25M
//
//公司:杭州自由电子科技
//电话:0571-85084089
//网址:www.freefpga.com
//邮件:tech@freefpga.com
//----------------------------------------------------------------
//1024 X 768 X 60
`define HOR_PIXELS 1344
`define HBLANK_START 1024
`define HSYNC_START 1048
`define HSYNC_TIME 136
`define VER_LINES 806
`define VBLANK_START 768
`define VSYNC_START 771
`define VSYNC_TIME 6
`define LINE_SIZE 4096
/*
// 800 X 600 X 60
`define HOR_PIXELS 1056
`define HBLANK_START 800
`define HSYNC_START 840
`define HSYNC_TIME 128
`define VER_LINES 628
`define VBLANK_START 600
`define VSYNC_START 601
`define VSYNC_TIME 6
`define LINE_SIZE 3200
*/
/*
// 640 X 480 X 60
`define HOR_PIXELS 800
`define HBLANK_START 640
`define HSYNC_START 659
`define HSYNC_TIME 96
`define VER_LINES 525
`define VBLANK_START 480
`define VSYNC_START 493
`define VSYNC_TIME 2
`define LINE_SIZE 2560
*/
module freedev_vga(
clk,
rst_n,
//从端口
s_irq,
s_chipselect_n,
s_read_n,
s_write_n,
s_address,
s_readdata,
s_writedata,
//主端口
m_waitrequest,
m_address,
m_read,
m_readdata,
m_write,
m_writedata,
m_byteenable,
m_burstcount,
m_readdatavalid,
//VGA输信号
pclk,
r ,
g ,
b ,
hsync ,
vsync ,
blank,
sync,
psave
);
input clk; // clk
input rst_n; // reset
//slave 接口信号
output s_irq; // interrupt request
input s_chipselect_n; // chip select
input s_read_n; // read signal
input s_write_n; // write signal
input [3:0]s_address; // address
output [31:0]s_readdata; // out data
input [31:0]s_writedata; // in data
//master 接口信号
input m_waitrequest; // 等待
output reg [31:0]m_address; // master 地址
output reg m_read; // 读信号
input [31:0]m_readdata; // 读数据
output reg m_write; // 写信号
output [31:0]m_writedata; // 写数据
output reg [3:0]m_byteenable; // 字节选择
output reg [7:0]m_burstcount; // 突发传输数
input m_readdatavalid; // 突发传输读数据有效
//VGA输信号
input pclk; // 输入象素时钟
output [7:0]r ; // 输出红
output [7:0]g ; // 输出绿
output [7:0]b ; // 输出蓝
output hsync ; // 输出行同步
output vsync ; // 输出场同步
output blank; // 输出消隐
output sync;
output psave;
//VGA输信号寄存器
reg [7:0]r ; // 输出红
reg [7:0]g ; // 输出绿
reg [7:0]b ; // 输出蓝
reg hsync ; // 输出行同步
reg vsync ; // 输出场同步
assign blank = 1'b1;
assign sync = 1'b1;
assign psave = 1'b1;
/////////////////////////////avalone slave部分//////////////////////////////////////
// 寄存器定义
reg [31:0] mode; // 模式寄存器 0x00
reg [31:0] command; // 命令寄存器 0x01
reg [31:0] status; // 状态寄存器 0x02
reg [31:0] irq_mask; // 中断屏蔽寄存器 0x03
reg [31:0] video_buff; // 显示缓存地址 0x04
reg rirq,wirq;
reg [31:0] s_readdata; // out data
// 模块软件复位
wire s_rst = command[0];
wire vga_enable = command[1]; // VGA显示控制位
wire mem_enable = command[2]; // 存储读取控制位
// 总线写信号
wire write_req = ~s_chipselect_n & ~s_write_n;
// 总线读信号
wire read_req = ~s_chipselect_n & ~s_read_n;
// 写寄存器
always @(posedge clk or negedge rst_n)
if (!rst_n )
begin
mode <= #1 32'h00000000; //模式寄存器清0
command <= #1 32'h00000000; //命令寄存器清0
irq_mask <= #1 32'hffffffff; //默认屏蔽中断
video_buff <= #1 32'hffff0000; //默认视频存储地址
end
else
begin
if ( write_req )
begin
case ( s_address )
4'b0000 : mode <= #1 s_writedata; // 写模式寄存器
4'b0001 : command <= #1 s_writedata; // 写命令
4'b0010 : status <= #1 s_writedata; // 状态
4'b0011 : irq_mask <= #1 s_writedata; // 写中断屏蔽寄存器
4'b0100 : video_buff <= #1 s_writedata; // 显示缓存地址
default: ;
endcase
end
end
always @(posedge clk)
begin
if( read_req )
case (s_address)
4'b0000: s_readdata <= #1 mode;
4'b0001: s_readdata <= #1 command;
4'b0010: s_readdata <= #1 status;
4'b0011: s_readdata <= #1 irq_mask;
4'b0100: s_readdata <= #1 video_buff;
4'b0101: s_readdata <= #1 {{22{1'b0}},wrusedw}; // fifo 读使用字节
4'b0110: s_readdata <= #1 {{22{1'b0}},rdusedw}; // fifo 写使用字节
4'b0111: s_readdata <= #1 {{30{1'b0}},rdempty,rdfull};
4'b1000: s_readdata <= #1 {{30{1'b0}},wrempty,wrfull};
4'b1001: s_readdata <= #1 fifo_line_use;
4'b1010: s_readdata <= #1 fifo_line_show;
4'b1011: s_readdata <= #1 fifo_line_show_end;
4'b1100: s_readdata <= #1 count639;
4'b1101: s_readdata <= #1 readdata;
4'b1110: s_readdata <= #1 32'h00000000;
4'b1111: s_readdata <= #1 32'h00000000;
endcase
end
///////////////////// VGA 时序 //////////////////////////////////
reg[10:0] pixcel_count; // 行计数寄存器
reg[9:0] line_count; // 场计数寄存器
reg hblank; // 行消隐
reg vblank; // 场笑隐
reg d_pclk;
wire [1:0]pclk_state={d_pclk,pclk};
// clk时钟同步处理pclk
always @(posedge clk)
begin
d_pclk <= pclk;
end
// 象素计数
always @(posedge clk or negedge rst_n)
if(~rst_n)
pixcel_count <= 0;
else if( pclk_state == 2'b01)
pixcel_count <= (pixcel_count == `HOR_PIXELS - 1) ? 0 : pixcel_count + 1;
// 读显示缓冲控制
always @(posedge clk or negedge rst_n)
if(~rst_n)
read_start <= 0;
else begin
if( (pclk_state == 2'b01) && ((line_count >0 && line_count < `VBLANK_START)||line_count==0) && (pixcel_count == `HSYNC_START))
read_start <= 1'b1;
if(read_start)
read_start <= 1'b0;
end
// 行消隐
always @(posedge clk or negedge rst_n)
if(~rst_n)
hblank <= 0;
else if( pclk_state == 2'b01) // pclk上升沿
begin
if(pixcel_count > `HBLANK_START - 1 && pixcel_count < `HOR_PIXELS - 1)
hblank <= 1;
else
hblank <= 0;
end
// 行同步
always @(posedge clk or negedge rst_n)
if(~rst_n)
hsync <= 1;
else if( pclk_state == 2'b01) // pclk上升沿
begin
if(pixcel_count >= `HSYNC_START - 1 && pixcel_count < `HSYNC_START + `HSYNC_TIME - 1)
hsync <= 1;
else
hsync <= 0;
end
reg [31:0]line_addr; // 行显示内存地址
//行计数
always @(posedge clk or negedge rst_n)
if(~rst_n)
line_count <= 0;
else if( pclk_state == 2'b01) // pclk上升沿
begin
if(pixcel_count == `HOR_PIXELS - 1)
line_count <= (line_count == `VER_LINES - 1) ? 0 : line_count + 1;
if(pixcel_count == 0)
begin
if (line_count == 0 )
line_addr <= video_buff ;
else
line_addr <= line_addr + `LINE_SIZE;
end
end
// 场消隐
always @(posedge clk or negedge rst_n)
if(~rst_n)
vblank <= 0;
else if( pclk_state == 2'b01) // pclk上升沿
begin
if(pixcel_count == `HOR_PIXELS - 1)
begin
if(line_count > `VBLANK_START - 1 && line_count < `VER_LINES - 1 )
vblank <= 1;
else
vblank <= 0;
end
end
// 场同步
always @(posedge clk or negedge rst_n)
if(~rst_n)
vsync <= 1;
else if( pclk_state == 2'b01) // pclk上升沿
begin
if(pixcel_count == `HOR_PIXELS - 1)
begin
if(line_count >= `VSYNC_START - 1 && line_count < `VSYNC_START + `VSYNC_TIME - 1 )
vsync <= 1;
else
vsync <= 0;
end
end
reg rdreq;
reg [31:0]rgb;
reg [31:0]fifo_line_show;
reg [31:0]fifo_line_show_end;
reg [31:0]read_fifo_count;
reg [31:0]count639;
// r,g,b 输出
always @(posedge pclk or negedge rst_n )
if(~rst_n)
begin
r <= 8'hFF;
g <= 8'hFF;
b <= 8'hFF;
rdreq <= 1'b0;
end else
begin
if((pixcel_count >= 0 && pixcel_count <`HBLANK_START) || pixcel_count == (`HOR_PIXELS-1)) // 0~639需要FIFO数据
begin
rdreq <= 1'b1;
if(rdempty )
begin
r <= 8'h00;
g <= 8'h00;
b <= 8'h00;
end else begin
r <= fifo_readdata[23:16];
g <= fifo_readdata[15:8];
b <= fifo_readdata[7:0];
end
end
else begin
rdreq <= 1'b0;
r <= 8'h00;
g <= 8'h00;
b <= 8'h00;
end
end
////////////////////////行数据读取控制///////////////////////////////////////////////////////////
parameter [3:0]
IDLE = 6'b0001, // 空闲 0x01
R_START0 = 6'b0010, // 读地址准备0 0x02
R_START1 = 6'b0100, // 等待wait无效 0x04
R_DATA = 6'b1000; // 读数据0 0x08
reg [31:0] readdata; // 读数据寄存器
reg [3:0] current_state; // 当前状态
reg [31:0] transfer_count; // 传输计数
reg [31:0] remain_count; // 剩余传输
reg [7:0] burstcount; // 突发传输次数
reg [31:0] count; // 一次突发传输内计数
reg [31:0] fifo_line_use;
reg read_start; // 读显示数据开始
reg only_one;
// Avalon Master读控制状态机
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
current_state <= #1 IDLE;
m_address <= #1 32'hzzzzzzzz;
m_read <= #1 1'b0;
m_byteenable <= #1 4'h0;
m_burstcount <= #1 8'h00;
transfer_count <= #1 32'h00000000;
end
else if(mem_enable == 1'b1)
begin
case(current_state)
IDLE: begin
m_address <= #1 32'hzzzzzzzz;
m_read <= #1 1'b0;
m_byteenable <= #1 4'h0;
transfer_count <= #1 32'h00000000;
if( read_start )
begin
fifo_line_use <= {{22{1'b0}},wrusedw}; // fifo 读使用字节
current_state <= #1 R_START0;
burstcount <= #1 128; // 突发传输次数
remain_count <= #1 `HBLANK_START; // 剩余传输数等于待传输数
end
else
current_state <= #1 IDLE;
end
R_START0: begin // 提交address、read、byteenable、burstcount
if( transfer_count == `HBLANK_START)
current_state <= #1 IDLE;
else begin
m_address <= #1 line_addr+ (transfer_count*4);
m_read <= #1 1'b1;
m_byteenable <= #1 4'hf;
m_burstcount <= #1 burstcount;
remain_count <= #1 remain_count - {{24{1'b0}},burstcount};//剩余传输数
count <= #1 32'h00000000;
current_state <= #1 R_DATA;
end
end
R_START1: begin
if( m_waitrequest == 1'b1) current_state <= #1 R_START1;
else begin
m_read <= #1 1'b0;
current_state <= #1 R_DATA;
end
end
R_DATA: begin
if( m_readdatavalid == 1'b0 ) // 数据无效等待
current_state <= #1 R_DATA;
else begin
readdata <= m_readdata; // m_readdata数据进FIFO
count <= count + 1;
if( count == (burstcount-1 )) //本次突发读传输完成
begin
m_read <= #1 1'b0;
m_byteenable <= #1 4'h0;
if( remain_count == 32'h00000000)
begin
current_state <= IDLE;
end
else begin
transfer_count <= #1 transfer_count+ burstcount;
burstcount <= #1 (remain_count < 128) ? {remain_count[6:0]}:128; // 下一次突发传输次数
current_state <= #1 R_START0; // 再一次启动读和写
end
end
else
current_state <= #1 R_DATA; //突发传输未完成,继续
end
end
default: current_state <= #1 IDLE;
endcase
end else
only_one <= 1'b0;
//////////////////////////// 视频缓冲FIFO ///////////////////////////////////////////////////////
//wire fifo_wrreq = (current_state == R_DATA) & m_readdatavalid; //FIFO 写请求
wire fifo_wrreq = m_readdatavalid; //FIFO 写请求
wire fifo_rdreq = rdreq; //FIFO 读请求
wire [9:0] rdusedw,wrusedw;
wire [31:0] fifo_readdata;
wire rdempty,rdfull;
wire wrempty,wrfull;
//缓存FIFO
vga_fifo line_fifo(
.aclr(s_rst), // 异步清除
.rdclk(pclk), // 读时钟
.rdreq(fifo_rdreq), // 读请求
.q(fifo_readdata), // 读数据
.rdfull(rdfull), // 读满标志
.rdempty(rdempty), // 读空标志
.rdusedw(rdusedw), // 读使用计数
.wrclk(clk), // 写时钟
.wrreq(fifo_wrreq), // 写请求
.data(m_readdata), // 写数据
.wrfull(wrfull), // 写满标志
.wrempty(wrempty), // 写空标志
.wrusedw(wrusedw) // 写使用计数
);
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -