当前位置:网站首页>Design of vga/lcd display controller system based on FPGA (Part 2)
Design of vga/lcd display controller system based on FPGA (Part 2)
2022-06-24 15:11:00 【FPGA technology Jianghu】
be based on FPGA Of VGA/LCD Display controller system design ( in )
Today, I bring you FPGA Of VGA/LCD Display controller design , Because of the long space , It is divided into three parts . Today brings the second , medium-length ,VGA Display principle and VGA/LCD Display the basic framework of the controller , Don't talk much , Loading .
There were also image processing and VGA Show related articles , Great Xia, you can search by yourself .
Source series : be based on FPGA Of VGA Drive design ( Source attached works )
be based on FPGA Real time image edge detection system design ( On )
be based on FPGA Real time image edge detection system design ( in )
be based on FPGA Real time image edge detection system design ( Next )
Reading guide
VGA (Video Graphics Array) Video graphics array , yes IBM On 1987 Annual follow PS/2 machine (PersonalSystem 2) A video transmission standard using analog signals . This standard is very outdated for today's PC market . But at that time, it had high resolution 、 The display speed is fast 、 Rich colors, etc , It has been widely used in the field of color display , It is a low standard supported by many manufacturers .
LCD ( Liquid Crystal Display For short ) Liquid crystal display .LCD The structure is to place a liquid crystal cell between two parallel glass substrates , The lower base plate is arranged on the glass TFT( Thin film transistor ), A color filter is arranged on the upper substrate glass , adopt TFT The rotation direction of liquid crystal molecules is controlled by changing the signal and voltage on the liquid crystal , So as to control whether the polarized light of each pixel is emitted or not and achieve the purpose of display . According to the different backlights ,LCD Can be divided into CCFL A display and a LED There are two types of monitors .LCD Has replaced CRT The mainstream , Prices have also fallen a lot , And has been fully popularized .
In the previous article, I introduced how to get 、 Process the video signal provided by the camera , In practical application, the processed signals need to be displayed on the display . This process is opposite to that in signal processing , The composition of digital signals according to the system of TV signals conforms to the time sequence 、 Signal with required format , And add various synchronization signals for control . This article will pass FPGA Achieve one VGA/LCD Displays an instance of the controller , And the implementation process is introduced in detail .
Part II summary : Introduction VGA/LCD Implementation of display controller program , Including top-level programs 、 Color lookup table 、 Color processor 、 Cursor processor 、 Video timing generator and output FIFO And so on .
3、 ... and 、VGA/LCD Implementation of display controller program
3.1 Top level program
The top-level program needs to connect and control each sub module , top floor vga_top The module code is as follows :
module vga_enh_top (…);
// Input and output
input wb_clk_i; // External clock input
input wb_rst_i; // Synchronous high effective restart signal
input rst_i; // Asynchronous restart signal
output wb_inta_o; // Interrupt request signal
….
// Connect the sub modules
vga_wb_slave wbs (
.clk_i ( wb_clk_i ),
….
);
….
// Read output FIFO An interrupt signal is generated when the content
always @(posedge clk_p_i)
luint_pclk <= #1 line_fifo_rreq & line_fifo_empty_rd;
always @(posedge wb_clk_i or negedge arst)
//ctrl_ven Is in the control register VEN position , It is the enabling bit of the display
// When the monitor is not working , Clear interrupt
if (!ctrl_ven)
begin
sluint <= #1 1'b0;
luint <= #1 1'b0;
end
else
begin
sluint <= #1 luint_pclk;
luint <= #1 sluint;
end
endmodule 3.2 Color lookup table --Color Lookup Table
The color lookup table saves 256 Color resolution R、G、B All possible colors , So it's a piece 256×24 Bit static RAM District , Each pixel consists of R、G、B Each color 8 Bit data composition , The program includes two such color lookup tables , altogether 512×24 position .
The main codes of the color lookup table are as follows :
module vga_csm_pb (clk_i, req0_i, ack0_o, adr0_i, dat0_i, dat0_o, we0_i, req1_i, ack1_o, adr1_i, dat1_i, dat1_o, we1_i);
// Parameter setting
// Set the data bus width
parameter DWIDTH = 32;
// Address bus width
parameter AWIDTH = 8;
// Input and output
// Clock input
input clk_i;
// Interface to host
input [ AWIDTH -1:0] adr0_i; // Address input signal
input [ DWIDTH -1:0] dat0_i; // Data input signal
output [ DWIDTH -1:0] dat0_o; // Data output signal
input we0_i; // Write enable input signal
input req0_i; // Access request input signal
output ack0_o; // Access reply output signal
input [ AWIDTH -1:0] adr1_i; // Address input signal
input [ DWIDTH -1:0] dat1_i; // Data input signal
output [ DWIDTH -1:0] dat1_o; // Data output signal
input we1_i; // Write enable input signal
input req1_i; // Access request input signal
output ack1_o; // Access reply output signal
// Variable declarations
// Multiple selection signals
wire acc0, acc1;
reg dacc0, dacc1;
wire sel0, sel1;
reg ack0, ack1;
// Memory data output
wire [DWIDTH -1:0] mem_q;
// Module body
// Generate multiple selection signals
assign acc0 = req0_i;
assign acc1 = req1_i && !sel0;
[email protected](posedge clk_i)
begin
dacc0 <= #1 acc0 & !ack0_o;
dacc1 <= #1 acc1 & !ack1_o;
end
assign sel0 = acc0 && !dacc0;
assign sel1 = acc1 && !dacc1;
[email protected](posedge clk_i)
begin
ack0 <= #1 sel0 && !ack0_o;
ack1 <= #1 sel1 && !ack1_o;
end
// Select input address signal 、 Data signals 、 Control signal, etc
wire [AWIDTH -1:0] mem_adr = sel0 ? adr0_i : adr1_i;
wire [DWIDTH -1:0] mem_d = sel0 ? dat0_i : dat1_i;
wire mem_we = sel0 ? req0_i && we0_i : req1_i && we1_i;
// Connect to pre-defined single channel memory
generic_spram #(AWIDTH, DWIDTH) clut_mem(
.clk(clk_i),
.rst(1'b0), // No restart
.ce(1'b1), // All the time
.we(mem_we),
.oe(1'b1), // Always output data
.addr(mem_adr),
.di(mem_d),
.do(mem_q)
);
// Specify data output
assign dat0_o = mem_q;
assign dat1_o = mem_q;
// Generate reply output
assign ack0_o = ( (sel0 && we0_i) || ack0 );
assign ack1_o = ( (sel1 && we1_i) || ack1 );
endmoduleA common memory is defined in the code , Apply to Altera、Xilinx Of FPGA product . The main codes are as follows :
module generic_spram(
// Universal SRAM Interface
clk, rst, ce, we, oe, addr, di, do
)
// Default address and data bus line width
parameter aw = 6; // Address bus line width
parameter dw = 8; // Data bus line width
// Universal SRAM Interface
input clk; // The clock , The rising edge is effective
input rst; // Reset signal , Highly effective
input ce; // Piece of optional signal , Highly effective
input we; // Write enable signal , Highly effective
input oe; // Output enable signal , Highly effective
input [aw-1:0] addr; // Address bus input
input [dw-1:0] di; // Input data bus
output [dw-1:0] do; // Output data bus
// Module body
// If it is universal FPGA
`ifdef VENDOR_FPGA
reg [dw-1:0] mem [(1<<aw) -1:0]
reg [aw-1:0] ra;
// Read operations
always @(posedge clk)
if (ce)
ra <= #1 addr;
assign #1 do = mem[ra];
// Write operations
always @(posedge clk)
if (we && ce)
mem[addr] <= #1 di;
`else
// If the XILINX The company's FPGA
`ifdef VENDOR_XILINX
wire [dw-1:0] q; // Output
//FPGA Memory instantiation
// Virtex/Spartan2 BlockRAMs
xilinx_ram_sp xilinx_ram(
.clk(clk),
.rst(rst),
.addr(addr),
.di(di),
.en(ce),
.we(we),
.do(do)
);
defparam
xilinx_ram.dwidth = dw,
xilinx_ram.awidth = aw;
`else
// If it is Altera The company's FPGA
`ifdef VENDOR_ALTERA
// use Altera FLEX Series of EABs
altera_ram_sp altera_ram(
.inclock(clk),
.address(addr),
.data(di),
.we(we && ce),
.q(do)
);
defparam
altera_ram.dwidth = dw,
altera_ram.awidth = aw;
`else
`else
// General mode
reg [dw-1:0] mem [(1<<aw)-1:0]; // RAM Content
wire [dw-1:0] q; // RAM Output
reg [aw-1:0] raddr; // RAM Read the address
// Data output
assign do = (oe) ? q : {dw{1'bz}};
// RAM Reading and writing
// Read operations
[email protected](posedge clk)
if (ce) // && !we)
raddr <= #1 addr;
assign #1 q = rst ? {dw{1'b0}} : mem[raddr];
// Write operations
[email protected](posedge clk)
if (ce && we)
mem[addr] <= #1 di;
`endif // !VENDOR_ALTERA
`endif // !VENDOR_XILINX
`endif // !VENDOR_FPGA
// use Altera The company's FPGA
`ifdef VENDOR_ALTERA
module altera_ram_sp (
address,
inclock,
we,
data,
q
);
parameter awidth = 7;
parameter dwidth = 8;
input [awidth -1:0] address;
input inclock;
input we;
input [dwidth -1:0] data;
output [dwidth -1:0] q;
syn_ram_irou #(
"UNUSED",
dwidth,
awidth,
1 << awidth
);
altera_spram_model (
.Inclock(inclock),
.Address(address),
.Data(data),
.WE(we),
.Q(q)
);
endmodule
`endif // VENDOR_ALTERA
// use XILINX The company's FPGA
`ifdef VENDOR_XILINX
module xilinx_ram_sp (
clk,
rst,
addr,
di,
en,
we,
do)
parameter awidth = 7;
parameter dwidth = 8;
input clk;
input rst;
input [awidth -1:0] addr;
input [dwidth -1:0] di;
input en;
input we;
output [dwidth -1:0] do;
C_MEM_SP_BLOCK_V1_0 #(
awidth,
1,
"0",
1 << awidth,
1,
1,
1,
1,
1,
1,
1,
"",
16,
0,
0,
1,
1,
dwidth
);
xilinx_spram_model (
.CLK(clk),
.RST(rst),
.ADDR(addr),
.DI(di),
.EN(en),
.WE(we),
.DO(do)
);
endmodule
`endif // VENDOR_XILINX3.3 Color processor --Color Processor
The color processor is responsible for generating the color of each pixel . This function consists of a color processor and an output FIFO Joint completion , The internal structure of the color processor is shown in the figure 5 Shown .
chart 5 Internal structure of color processor
The color processor includes an address generator 、 Data buffer and colorization module :
- Address generator While generating the address of the video memory , The address generator operates the switching of memory blocks and records the number of pixels to be read . When all pixels are read , Switch the block position of the memory .
- Data buffering Temporarily save the data read from the video memory , Access to data can be made according to consecutive addresses . All data is stored in consecutive addresses .8 In bit mode , One 32 Bit word save 4 Pixel data ;16 In bit mode , One 32 Bit word save 2 Pixel ;24 In bit mode , One 32 Bit word save 1 1/3 Pixel ;32 In bit mode , One 32 Bit word save 1 Pixel .
- Colorization module Convert the data stored in the data buffer into color data , And the output .
The main code of the color processor is as follows :
module vga_colproc(clk, srst, vdat_buffer_di, ColorDepth, PseudoColor,
vdat_buffer_empty, vdat_buffer_rreq, rgb_fifo_full,
rgb_fifo_wreq, r, g, b,
clut_req, clut_ack, clut_offs, clut_q
);
// Input 、 Output
input clk; // Input clock
input srst; // Synchronous reset signal
input [31:0] vdat_buffer_di; // Video memory data input
input [1:0] ColorDepth; // Color depth (8 position 、16 position 、24 Bit mode )
input PseudoColor; // False color enable
input vdat_buffer_empty;
output vdat_buffer_rreq; // Read buffer request
reg vdat_buffer_rreq;
input rgb_fifo_full;
output rgb_fifo_wreq;
reg rgb_fifo_wreq;
output [7:0] r, g, b; // Pixel color information
reg [7:0] r, g, b;
output clut_req; // Color lookup table request
reg clut_req;
input clut_ack; // Color lookup table answer
output [ 7:0] clut_offs; // Color lookup table offset
reg [7:0] clut_offs;
input [23:0] clut_q; // Color lookup table data input
// variable declaration
reg [31:0] DataBuffer;
reg [7:0] Ra, Ga, Ba;
reg [1:0] colcnt;
reg RGBbuf_wreq;
// Module content
always @(posedge clk)
if (vdat_buffer_rreq)
DataBuffer <= #1 vdat_buffer_di;
// State machine
// Expand the data read from the data buffer
parameter idle = 7'b000_0000,
fill_buf = 7'b000_0001,
bw_8bpp = 7'b000_0010,
col_8bpp = 7'b000_0100,
col_16bpp_a = 7'b000_1000,
col_16bpp_b = 7'b001_0000,
col_24bpp = 7'b010_0000,
col_32bpp = 7'b100_0000;
reg [6:0] c_state; // synopsys enum_state
reg [6:0] nxt_state; // synopsys enum_state
// State machine
always @(c_state or vdat_buffer_empty or ColorDepth or PseudoColor or rgb_fifo_full or colcnt or clut_ack)
begin : nxt_state_decoder
// initialization
nxt_state = c_state;
case (c_state)
// Idle state
idle:
// If the data buffer is not empty , data FIFO In case of dissatisfaction , Start filling in the data
if (!vdat_buffer_empty && !rgb_fifo_full)
nxt_state = fill_buf;
// Fill the data buffer with data FIFO in
fill_buf:
// Color mode judgment
case (ColorDepth)
2'b00:
// Pseudo color
if (PseudoColor)
nxt_state = col_8bpp;
else
nxt_state = bw_8bpp;
//16 Bit mode
2'b01:
nxt_state = col_16bpp_a;
//24 Bit mode
2'b10:
nxt_state = col_24bpp;
//32 Bit mode
2'b11:
nxt_state = col_32bpp;
endcase
//8 Bit black and white mode
bw_8bpp:
if (!rgb_fifo_full && !(|colcnt) )
if (!vdat_buffer_empty)
nxt_state = fill_buf;
else
nxt_state = idle;
//8 Bit color mode
col_8bpp:
if (!(|colcnt))
if (!vdat_buffer_empty && !rgb_fifo_full)
nxt_state = fill_buf;
else
nxt_state = idle;
// 16 Bit color mode
col_16bpp_a:
if (!rgb_fifo_full)
nxt_state = col_16bpp_b;
col_16bpp_b:
if (!rgb_fifo_full)
if (!vdat_buffer_empty)
nxt_state = fill_buf;
else
nxt_state = idle;
// 24 Bit color mode
col_24bpp:
if (!rgb_fifo_full)
if (colcnt == 2'h1) // (colcnt == 1)
nxt_state = col_24bpp; // Stay in the current state
else if (!vdat_buffer_empty)
nxt_state = fill_buf;
else
nxt_state = idle;
// 32 Bit color mode
col_32bpp:
if (!rgb_fifo_full)
if (!vdat_buffer_empty)
nxt_state = fill_buf;
else
nxt_state = idle;
endcase
end
// Generate status register
always @(posedge clk)
if (srst)
c_state <= #1 idle;
else
c_state <= #1 nxt_state;
reg iclut_req;
reg ivdat_buf_rreq;
reg [7:0] iR, iG, iB, iRa, iGa, iBa;
// Output decoding
always @(c_state or vdat_buffer_empty or colcnt or DataBuffer or rgb_fifo_full or clut_ack or clut_q or Ba or Ga or Ra)
begin : output_decoder
// Initialization value
ivdat_buf_rreq = 1'b0;
RGBbuf_wreq = 1'b0;
iclut_req = 1'b0;
iR = 'h0;
iG = 'h0;
iB = 'h0;
iRa = 'h0;
iGa = 'h0;
iBa = '
case (c_state)
// Idle state
idle:
begin
// preservation RGB Data FIFO Non empty
if (!rgb_fifo_full)
if (!vdat_buffer_empty)
ivdat_buf_rreq = 1'b1;
// Enter into 8 Bit pseudo color mode
RGBbuf_wreq = clut_ack;
iR = clut_q[23:16];
iG = clut_q[15: 8];
iB = clut_q[ 7: 0];
end
// Fill the cache with data
fill_buf:
begin
// Get into 8 Bit pseudo color mode
RGBbuf_wreq = clut_ack;
iR = clut_q[23:16];
iG = clut_q[15: 8];
iB = clut_q[ 7: 0];
end
// 8 Bit black North mode
bw_8bpp:
begin
if (!rgb_fifo_full)
begin
RGBbuf_wreq
if ( (!vdat_buffer_empty) && !(|colcnt) )
ivdat_buf_rreq = 1'b1;
end
case (colcnt)
2'b11:
begin
iR = DataBuffer[31:24];
iG = DataBuffer[31:24];
iB = DataBuffer[31:24];
end
2'b10:
begin
iR = DataBuffer[23:16];
iG = DataBuffer[23:16];
iB = DataBuffer[23:16];
end
2'b01:
begin
iR = DataBuffer[15:8];
iG = DataBuffer[15:8];
iB = DataBuffer[15:8];
end
default:
begin
iR = DataBuffer[7:0];
iG = DataBuffer[7:0];
iB = DataBuffer[7:0];
end
endcase
end
//8 Bit mode
col_8bpp:
begin
if (!(|colcnt))
if (!vdat_buffer_empty && !rgb_fifo_full)
ivdat_buf_rreq
RGBbuf_wreq = clut_ack;
iR = clut_q[23:16];
iG = clut_q[15: 8];
iB = clut_q[ 7: 0];
iclut_req = !rgb_fifo_full || (colcnt[1] ^ colcnt[0]);
end
//16 Bit color mode
col_16bpp_a:
begin
if (!rgb_fifo_full)
RGBbuf_wreq = 1'b1;
iR[7:3] = DataBuffer[31:27];
iG[7:2] = DataBuffer[26:21];
iB[7:3] = DataBuffer[20:16];
end
col_16bpp_b:
begin
if (!rgb_fifo_full)
begin
RGBbuf_wreq = 1'b1;
if (!vdat_buffer_empty)
ivdat_buf_rreq = 1'b1;
end
iR[7:3] = DataBuffer[15:11];
iG[7:2] = DataBuffer[10: 5];
iB[7:3] = DataBuffer[ 4: 0];
end
// 24 Bit color mode
col_24bpp:
begin
if (!rgb_fifo_full)
begin
RGBbuf_wreq
if ( (colcnt != 2'h1) && !vdat_buffer_empty)
ivdat_buf_rreq = 1'b1;
end
case (colcnt) // synopsis full_case parallel_case
2'b11:
begin
iR = DataBuffer[31:24];
iG = DataBuffer[23:16];
iB = DataBuffer[15: 8];
iRa = DataBuffer[ 7: 0];
end
2'b10:
begin
iR = Ra;
iG = DataBuffer[31:24];
iB = DataBuffer[23:16];
iRa = DataBuffer[15: 8];
iGa = DataBuffer[ 7: 0];
end
2'b01:
begin
iR = Ra;
iG = Ga;
iB = DataBuffer[31:24];
iRa = DataBuffer[23:16];
iGa = DataBuffer[15: 8];
iBa = DataBuffer[ 7: 0];
end
default:
begin
iR = Ra;
iG = Ga;
iB = Ba;
end
endcase
end
// 32 Bit color mode
col_32bpp:
begin
if (!rgb_fifo_full)
begin
RGBbuf_wreq = 1'b1;
if (!vdat_buffer_empty)
ivdat_buf_rreq = 1'b1;
end
iR[7:0] = DataBuffer[23:16];
iG[7:0] = DataBuffer[15:8];
iB[7:0] = DataBuffer[7:0];
end
endcase
end
// Generate output register
always @(posedge clk)
begin
r <= #1 iR;
g <= #1 iG;
b <= #1 iB;
if (RGBbuf_wreq)
begin
Ra <= #1 iRa;
Ba <= #1 iBa;
Ga <= #1 iGa;
end
if (srst)
begin
vdat_buffer_rreq <= #1 1'b0;
rgb_fifo_wreq <= #1 1'b0;
clut_req <= #1 1'b0;
end
else
begin
vdat_buffer_rreq <= #1 ivdat_buf_rreq;
rgb_fifo_wreq <= #1 RGBbuf_wreq;
clut_req <= #1 iclut_req;
end
end
// Color lookup table offset
always @(colcnt or DataBuffer)
case (colcnt) // synopsis full_case parallel_case
2'b11: clut_offs = DataBuffer[31:24];
2'b10: clut_offs = DataBuffer[23:16];
2'b01: clut_offs = DataBuffer[15: 8];
2'b00: clut_offs = DataBuffer[ 7: 0];
endcase
// Color counter
always @(posedge clk)
if (srst)
colcnt <= #1 2'b11;
else if (RGBbuf_wreq)
colcnt <= #1 colcnt -2'h1;
endmodule 3.4 Cursor processor --Cursor Processor
VGA/LCD The display controller also provides a hardware cursor , It can be for GUI( Graphical user interface ,Graphics UserInterface) Provide an arrow like cursor , Pictured 6 Shown .
chart 6 Cursor provided by cursor processor
The cursor is formed by a cursor processor (Cursor Processor) complete . The program provides... For each cursor template 16kbit Space , The resolution of the cursor can be selected , There are two types of templates :
32×32 Pixel mode In this template , Each pixel data is saved in 16 Bit byte . 64×64 Pixel mode In this template , Each pixel data is saved in 4 Bit byte .
The program structure of cursor processor is shown in Figure 7 Shown .
chart 7 Program structure of cursor processor
When copying cursor to cursor data buffer , The address generator generates the memory address needed for the write operation . The cursor data buffer provides a block 512×32 Bit SRAM, Data used to save the cursor . The cursor processor is responsible for tracking the position of the cursor , Decide whether the cursor template needs to be updated 、 Whether the cursor needs to be displayed, etc .
The main code of cursor processor is as follows :
module vga_curproc (clk, rst_i, Thgate, Tvgate, idat, idat_wreq,
cursor_xy, cursor_en, cursor_res,
cursor_wadr, cursor_wdat, cursor_we,
cc_adr_o, cc_dat_i,
rgb_fifo_wreq, rgb);
// Input and output
input clk; // Clock input
input rst_i; // Synchronous high effective reset signal
// Image size
input [15:0] Thgate, Tvgate; // Horizontal and vertical dimensions
// Image data
input [23:0] idat; // Input image data
input idat_wreq; // Image data write request
// Cursor data
input [31:0] cursor_xy; // Cursor coordinates
input cursor_en; // Cursor valid flag
input cursor_res; // Cursor resolution
input [ 8:0] cursor_wadr; // Cursor buffer write address
input [31:0] cursor_wdat; // Cursor buffer writes data
input cursor_we; // Cursor buffer write valid
// Color register interface
output [ 3:0] cc_adr_o; // Cursor color register address
reg [ 3:0] cc_adr_o;
input [15:0] cc_dat_i; // Cursor color register data
// And FIFO The record of
output rgb_fifo_wreq; // RGB Data output request
reg rgb_fifo_wreq;
output [23:0] rgb; // RGB Data output
reg [23:0] rgb;
// variable declaration
reg dcursor_en, ddcursor_en, dddcursor_en;
reg [15:0] xcnt, ycnt;
wire xdone, ydone;
wire [15:0] cursor_x, cursor_y;
wire cursor_isalpha;
reg [15:0] cdat, dcdat;
wire [ 7:0] cursor_r, cursor_g, cursor_b, cursor_alpha;
reg inbox_x, inbox_y;
wire inbox;
reg dinbox, ddinbox, dddinbox;
reg [23:0] didat, ddidat, dddidat;
reg didat_wreq, ddidat_wreq;
wire [31:0] cbuf_q;
reg [11:0] cbuf_ra;
reg [ 2:0] dcbuf_ra;
wire [ 8:0] cbuf_a;
reg store1, store2;
// Procedural subject
// produce x、y The counter of
[email protected](posedge clk)
if(rst_i || xdone)
xcnt <= #1 16'h0;
else if (idat_wreq)
xcnt <= #1 xcnt + 16'h1;
assign xdone = (xcnt == Thgate) && idat_wreq;
[email protected](posedge clk)
if(rst_i || ydone)
ycnt <= #1 16'h0;
else if (xdone)
ycnt <= #1 ycnt + 16'h1;
assign ydone = (ycnt == Tvgate) && xdone;
// Decode cursor position , Decompose into two coordinates
assign cursor_x = cursor_xy[15: 0];
assign cursor_y = cursor_xy[31:16];
// produce inbox The signal
[email protected](posedge clk)
begin
inbox_x <= #1 (xcnt >= cursor_x) && (xcnt < (cursor_x + (cursor_res ? 16'h7f : 16'h1f) ));
inbox_y <= #1 (ycnt >= cursor_y) && (ycnt < (cursor_y + (cursor_res ? 16'h7f : 16'h1f) ));
end
assign inbox = inbox_x && inbox_y;
[email protected](posedge clk)
dinbox <= #1 inbox;
[email protected](posedge clk)
if (didat_wreq)
ddinbox <= #1 dinbox;
[email protected](posedge clk)
dddinbox <= #1 ddinbox;
// Generate cursor buffer address counter
[email protected](posedge clk)
if (!cursor_en || ydone)
cbuf_ra <= #1 12'h0;
else if (inbox && idat_wreq)
cbuf_ra <= #1 cbuf_ra +12'h1;
[email protected](posedge clk)
dcbuf_ra <= #1 cbuf_ra[2:0];
assign cbuf_a = cursor_we ? cursor_wadr : cursor_res ? cbuf_ra[11:3] : cbuf_ra[9:1];
// Connect to cursor memory
generic_spram #(9, 32) cbuf(
.clk(clk),
.rst(1'b0), // No reset
.ce(1'b1), // Always working
.we(cursor_we),
.oe(1'b1), // Always output data
.addr(cbuf_a),
.di(cursor_wdat),
.do(cbuf_q)
);
// stay 32×32 Decode cursor data in pixel mode
[email protected](posedge clk)
if (didat_wreq)
cdat <= #1 dcbuf_ra[0] ? cbuf_q[31:16] : cbuf_q[15:0];
[email protected](posedge clk)
dcdat <= #1 cdat;
// stay 64×64 Decode cursor data in pixel mode
// Generate cursor color address
[email protected](posedge clk)
if (didat_wreq)
case (dcbuf_ra)
3'b000: cc_adr_o <= cbuf_q[ 3: 0];
3'b001: cc_adr_o <= cbuf_q[ 7: 4];
3'b010: cc_adr_o <= cbuf_q[11: 8];
3'b011: cc_adr_o <= cbuf_q[15:12];
3'b100: cc_adr_o <= cbuf_q[19:16];
3'b101: cc_adr_o <= cbuf_q[23:20];
3'b110: cc_adr_o <= cbuf_q[27:24];
3'b111: cc_adr_o <= cbuf_q[31:28];
endcase
// Generate cursor color
assign cursor_isalpha = cursor_res ? cc_dat_i[15] : dcdat[15];
assign cursor_alpha = cursor_res ? cc_dat_i[7:0] : dcdat[7:0];
assign cursor_r = {cursor_res ? cc_dat_i[14:10] : dcdat[14:10], 3'h0};
assign cursor_g = {cursor_res ? cc_dat_i[ 9: 5] : dcdat[ 9: 5], 3'h0};
assign cursor_b = {cursor_res ? cc_dat_i[ 4: 0] : dcdat[ 4: 0], 3'h0};
// Delay image data
[email protected](posedge clk)
didat <= #1 idat;
[email protected](posedge clk)
if (didat_wreq)
ddidat <= #1 didat;
[email protected](posedge clk)
dddidat <= #1 ddidat;
[email protected](posedge clk)
begin
didat_wreq <= #1 idat_wreq;
ddidat_wreq <= #1 didat_wreq;
end
// Generate the selected unit
[email protected](posedge clk)
dcursor_en <= #1 cursor_en;
[email protected](posedge clk)
if (didat_wreq)
ddcursor_en <= #1 dcursor_en;
[email protected](posedge clk)
dddcursor_en <= #1 ddcursor_en;
[email protected](posedge clk)
if (ddidat_wreq)
if (!dddcursor_en || !dddinbox)
rgb <= #1 dddidat;
else if (cursor_isalpha)
`ifdef VGA_HWC_3D
rgb <= #1 dddidat * cursor_alpha;
`else
rgb <= #1 dddidat;
`endif
else
rgb <= #1 {cursor_r, cursor_g, cursor_b};
// Generate a write request signal
[email protected](posedge clk)
if (rst_i)
begin
store1 <= #1 1'b0;
store2 <= #1 1'b0;
end
else
begin
store1 <= #1 didat_wreq | store1;
store2 <= #1 (didat_wreq & store1) | store2;
end
[email protected](posedge clk)
rgb_fifo_wreq <= #1 ddidat_wreq & store2;
endmodule3.5 Video timing generator --Video Timing Generator
The video timing generator generates the synchronization signal necessary for the correct display of the image — Horizontal synchronization signal 、 Vertical sync signal .
1) Horizontal synchronization signal of video signal
The horizontal synchronization signal is shown in the figure 8 Shown .
chart 8 Horizontal synchronization signal
Thsync Indicates the time of the horizontal synchronization process , Measure in pixel beats .Thgdel Is the horizontal gate delay time , Indicates the time from the end of synchronization to the start of horizontal gate signal .Thgate Represents the time in the visible area of a video line .Thlen Indicates the length of time for the entire horizontal synchronization .
2) Vertical synchronization signal of video signal
The vertical synchronization signal is shown in the figure 9 Shown .
chart 9 Vertical sync signal
Tvsync Indicates the time of the vertical synchronization process , Measure in line beat .Tvgdel Is the vertical door delay time , Indicates the time from the end of synchronization to the start of vertical door signal .Tvgate Represents the time in the visible area of a video signal .Tvlen Indicates the length of time for the entire horizontal synchronization .
The main code of the video timing generator is as follows :
module vga_tgen(
clk, clk_ena, rst,
Thsync, Thgdel, Thgate, Thlen, Tvsync, Tvgdel, Tvgate, Tvlen,
eol, eof, gate, hsync, vsync, csync, blank
)
// Input and output
input clk;
input clk_ena;
input rst;
// Horizontal timing setting input signal
input [ 7:0] Thsync; // Horizontal sync signal width
input [ 7:0] Thgdel; // Horizontal synchronizing gate delay
input [15:0] Thgate; // Horizontal door ( The number of visible pixels per line of video signal )
input [15:0] Thlen; // The length of the horizontal synchronization signal ( Number of pixels per line of video signal )
// Vertical timing setting input signal
input [ 7:0] Tvsync; // Vertical sync signal width
input [ 7:0] Tvgdel; // Development of vertical synchronous door
input [15:0] Tvgate; // Vertical door ( The number of visible pixels per video signal )
input [15:0] Tvlen; // The length of the vertical synchronization signal ( Number of pixel lines per video signal )
// Output
output eol; // The end of a line of signals
output eof; // The end of an image
output gate; // Vertical and horizontal door signals
output hsync; // Horizontal synchronization signal
output vsync; // Vertical sync signal
output csync; // Composite synchronization signal
output blank; // Blank signal
// variable declaration
wire Hgate, Vgate;
wire Hdone;
// Procedural subject
// Connect the horizontal timing generator
vga_vtim hor_gen(
.clk(clk),
.ena(clk_ena),
.rst(rst),
.Tsync(Thsync),
.Tgdel(Thgdel),
.Tgate(Thgate),
.Tlen(Thlen),
.Sync(hsync),
.Gate(Hgate),
.Done(Hdone)
);
// Connect the vertical timing generator
wire vclk_ena = Hdone & clk_ena;
vga_vtim ver_gen(
.clk(clk),
.ena(vclk_ena),
.rst(rst),
.Tsync(Tvsync),
.Tgdel(Tvgdel),
.Tgate(Tvgate),
.Tlen(Tvlen),
.Sync(vsync),
.Gate(Vgate),
.Done(eof)
);
// Specify the output
assign eol = Hdone;
assign gate = Hgate & Vgate;
assign csync = hsync | vsync;
assign blank = ~gate;
endmoduleThe main codes generated by line synchronization and field synchronization signals are as follows :
module vga_vtim(clk, ena, rst, Tsync, Tgdel, Tgate, Tlen, Sync, Gate, Done);
// Input and output
input clk; // Clock signal
input ena; // Count enable
input rst; // Synchronous reset signal , Highly effective
input [ 7:0] Tsync; // Synchronization time
input [ 7:0] Tgdel; // Gate delay
input [15:0] Tgate; // Time of door signal
input [15:0] Tlen; // Line time / Field time
output Sync; // Output synchronization signal
output Gate; // Door signal
output Done; // That's ok / The end of the field
reg Sync;
reg Gate;
reg Done;
// Procedural subject
// Generate a timed state machine
reg [15:0] cnt, cnt_len;
wire [16:0] cnt_nxt, cnt_len_nxt;
wire cnt_done, cnt_len_done;
assign cnt_nxt = {1'b0, cnt} -17'h1;
assign cnt_done = cnt_nxt[16];
assign cnt_len_nxt = {1'b0, cnt_len} -17'h1;
assign cnt_len_done = cnt_len_nxt[16];
reg [4:0] state;
parameter [4:0] idle_state = 5'b00001;
parameter [4:0] sync_state = 5'b00010;
parameter [4:0] gdel_state = 5'b00100;
parameter [4:0] gate_state = 5'b01000;
parameter [4:0] len_state = 5'b10000;
always @(posedge clk)
// Reset
if (rst)
begin
state <= #1 idle_state;
cnt <= #1 16'h0;
cnt_len <= #1 16'b0;
Sync <= #1 1'b0;
Gate <= #1 1'b0;
Done <= #1 1'b0;
end
else if (ena)
begin
cnt <= #1 cnt_nxt[15:0];
cnt_len <= #1 cnt_len_nxt[15:0];
Done <= #1 1'b0;
case (state)
// Idle state
idle_state:
begin
state <= #1 sync_state;
cnt <= #1 Tsync;
cnt_len <= #1 Tlen;
Sync <= #1 1'b1;
end
// Sync
sync_state:
if (cnt_done)
begin
state <= #1 gdel_state;
cnt <= #1 Tgdel;
Sync <= #1 1'b0;
end
// Gate delay
gdel_state:
if (cnt_done)
begin
state <= #1 gate_state;
cnt <= #1 Tgate;
Gate <= #1 1'b1;
end
// door
gate_state:
if (cnt_done)
begin
state <= #1 len_state;
Gate <= #1 1'b0;
end
// Total length
len_state:
if (cnt_len_done)
begin
state <= #1 sync_state;
cnt <= #1 Tsync;
cnt_len <= #1 Tlen;
Sync <= #1 1'b1;
Done <= #1 1'b1;
end
endcase
end
endmoduld3.6 Output FIFO
Output FIFO Used to ensure continuous data flow output to VGA perhaps LCD On the monitor .
Output FIFO The main code of is as follows :
module vga_fifo_dc (rclk, wclk, aclr, wreq, d, rreq, q, rd_empty, rd_full, wr_empty, wr_full);
// Parameter setting
parameter AWIDTH = 7; //128 An entrance
parameter DWIDTH = 16; //16bit Data bus width
// Input and output
input rclk; // Read the clock
input wclk; // Write clock
input aclr; // Asynchronous clear signal , Low efficiency
input wreq; // Write request signal
input [DWIDTH -1:0] d; // data input
input rreq; // Read request
output [DWIDTH -1:0] q; // Data output
output rd_empty; // FIFO Empty flag , Synchronize with the read clock
reg rd_empty;
output rd_full; // FIFO Full sign , Synchronize with the read clock
reg rd_full;
output wr_empty; // FIFO Empty flag , Synchronize with the write clock
reg wr_empty;
output wr_full; // FIFO Full sign , Synchronize with the write clock
reg wr_full;
// variable declaration
reg [AWIDTH -1:0] rptr, wptr;
wire ifull, iempty;
reg rempty, rfull, wempty, wfull;
// Procedural subject
// Read pointer
[email protected](posedge rclk or negedge aclr)
if (~aclr)
rptr <= #1 0;
else if (rreq)
rptr <= #1 rptr + 1;
// The write pointer
[email protected](posedge wclk or negedge aclr)
if (~aclr)
wptr <= #1 0;
else if (wreq)
wptr <= #1 wptr +1;
// Status flag
wire [AWIDTH -1:0] tmp;
wire [AWIDTH -1:0] tmp2;
assign tmp = wptr - rptr;
assign iempty = (rptr == wptr) ? 1'b1 : 1'b0;
assign tmp2 = (1 << AWIDTH) -3;
assign ifull = ( tmp >= tmp2 ) ? 1'b1 : 1'b0;
// Read the clock sign
[email protected](posedge rclk or negedge aclr)
if (~aclr)
begin
rempty <= #1 1'b1;
rfull <= #1 1'b0;
rd_empty <= #1 1'b1;
rd_full <= #1 1'b0;
end
else
begin
rempty <= #1 iempty;
rfull <= #1 ifull;
rd_empty <= #1 rempty;
rd_full <= #1 rfull;
end
// Write clock flag
[email protected](posedge wclk or negedge aclr)
if (~aclr)
begin
wempty <= #1 1'b1;
wfull <= #1 1'b0;
wr_empty <= #1 1'b1;
wr_full <= #1 1'b0;
end
else
begin
wempty <= #1 iempty;
wfull <= #1 ifull;
wr_empty <= #1 wempty;
wr_full <= #1 wfull;
end
// Connect to dual port memory
generic_dpram #(AWIDTH, DWIDTH) fifo_dc_mem(
.rclk(rclk),
.rrst(1'b0),
.rce(1'b1),
.oe(1'b1),
.raddr(rptr),
.do(q),
.wclk(wclk),
.wrst(1'b0),
.wce(1'b1),
.we(wreq),
.waddr(wptr),
.di(d)
);
endmoduleThis is the end of this article , The next one is based on FPGA Of VGA/LCD Display controller design ( Next ), Program simulation, test and summary .
边栏推荐
- Wide measuring range of jishili electrometer
- laravel下视图间共享数据
- A simple and powerful developer toolkit box3 cc
- Common singleton mode & simple factory
- In the eyes of the universe, how to correctly care about counting East and West?
- GO语言并发模型-MPG模型
- Linux Installation cenos7 MySQL - 8.0.26
- tongweb使用之端口冲突处理办法
- GO语言-init()函数-包初始化
- How to avoid placing duplicate orders
猜你喜欢

Bert-whitening 向量降维及使用

As a developer, what is the most influential book for you?

In the eyes of the universe, how to correctly care about counting East and West?

Application of motion capture system in positioning and mapping of mobile robot in underground tunnel

PgSQL queries the largest or smallest data of a field in a group

A brief introduction to the lexical analysis of PostgreSQL

Common sense knowledge points

box-sizing

不要小看了积分商城,它的作用可以很大

Stm32f1 and stm32cubeide programming examples -ws2812b full color LED driver (based on spi+dma)
随机推荐
leetcode. 12 --- integer to Roman numeral
I have been in the industry for 4 years and have changed jobs twice. I have learned a lot about software testing
安防市场进入万亿时代,安防B2B网上商城系统精准对接深化企业发展路径
Py之toad:toad的简介、安装、使用方法之详细攻略
Daily knowledge popularization
Chapter 8 operation bit and bit string (4)
一个简单而功能强大的开发者工具箱Box3.cc
The "little giant" specialized in special new products is restarted, and the "enterprise cloud" digital empowerment
GO语言并发模型-MPG模型
laravel下视图间共享数据
【ansible问题处理】远程执行用户环境变量加载问题
Is financial management of securities account safe??
10_ Those high-profile personal signatures
From pair to unordered_ Map, theory +leetcode topic practice
在宇宙的眼眸下,如何正确地关心东数西算?
15 differences between MES in process and discrete manufacturing enterprises (Part 2)
大智慧开户要选什么证券公司比较好,更安全一点
IDEA 插件 Material Theme UI收费后的办法
Is it safe to open an account in flush? What preparation is needed
从pair到unordered_map,理论+leetcode题目实战