当前位置:网站首页>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 .
边栏推荐
- Restoring to an earlier version in CVS
- Bitmap of redis data structure
- C language ---18 function (user-defined function)
- 探索云原生数据库,纵观未来科技发展
- From pair to unordered_ Map, theory +leetcode topic practice
- Do you really know the difference between H5 and applet?
- Qunhui synchronizes with alicloud OSS
- June training (day 23) - dictionary tree
- 时间同步业务的闭环管理——时间监测
- postgresql之词法分析简介
猜你喜欢

IDEA 插件 Material Theme UI收费后的办法

MySQL log management, backup and recovery

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

简谈企业Power BI CI /CD 实施框架

GO语言-goroutine协程的使用

Brief discussion on the implementation framework of enterprise power Bi CI /cd

Keras deep learning practice (11) -- visual neural network middle layer output

Don't underestimate the integral mall. It can play a great role

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

Laravel 8 realizes auth login
随机推荐
港股上市公司公告 API 数据接口
Detailed explanation of redis data types
ES mapping之keyword;term查询添加keyword查询;更改mapping keyword类型
Is industrial securities reliable? Is it safe to open a securities account?
update+catroot+c000021a+critical service failed+drivers+intelide+viaide+000000f
Openinstall joins hands with the book chain to help channel data analysis and create the era of Book Networking
六月集训(第23天) —— 字典树
R language constructs regression model diagnosis (normality is invalid), performs variable transformation, and uses powertransform function in car package to perform box Cox transform to normality on
Chapter 8 operation bit and bit string (4)
Go language -init() function - package initialization
Is it safe to open an account for stock speculation in the top ten securities app rankings in China
PgSQL queries the largest or smallest data of a field in a group
Actual combat | a tortuous fishing counteraction
How do individuals open accounts for stock speculation? Is it safe to open accounts for stock speculation
Step by step introduction to sqlsugar based development framework (9) -- Realizing field permission control with WinForm control
09_ An efficient memory method
Laravel 8 realizes auth login
同样是初级测试工程师,为啥他薪资高?会这几点面试必定出彩
leetcode 139. Word break word split (medium)
Record the range of data that MySQL update will lock