### 图形化LCD的显示 #### 显示屏的介绍 #### 视频产生 parameter ScreenWidth = 480; parameter ScreenHeight = 320; reg [6:0] CounterX; // counts from 0 to 119 reg [8:0] CounterY; // counts from 0 to 319 wire CounterXmaxed = (CounterX==ScreenWidth/4-1); wire CounterYmaxed = (CounterY==ScreenHeight-1); always @(posedge clk) begin if(CounterXmaxed) CounterX <= 0; else CounterX <= CounterX + 1; end always @(posedge clk) if(CounterXmaxed) begin if(CounterYmaxed) CounterY <= 0; else CounterY <= CounterY + 1; end reg HSync, VSync; always @(posedge clk) begin HSync <= CounterXmaxed; VSync <= CounterYmaxed; end #### 在屏幕上画图 // Use a blockram to hold the graphical data wire [7:0] BitmapData; blockram_8x512 RAM_bitmap(.clk(clk), .rd_adr({CounterY[4:0],CounterX[4:1]}), .data_out(BitmapData)); // Let's say we need 4 bits at a time wire [3:0] LCD_Bitmap4 = CounterX[0] ? BitmapData[3:0] : BitmapData[7:4]; // Display the data into a chessboard pattern wire [3:0] LCD_BitmapChessboard = (CounterY[5] ^ CounterX[5]) ? 4'b000 : LCD_Bitmap4 ^ {4{CounterY[5]}}; // We assume CounterX and CounterY are available: // CounterX is the pixel number of the current line // CounterY is the line number // We use a RAM to hold the "Y" values // Y=F(CounterX) wire [7:0] RAM_Y_value; blockram_8x512 RAM_FXY(.clk(clk), .rd_adr(CounterX), .data_out(RAM_Y_value)); // check for equality between the "Y" values and "CounterY" reg grcpeq1; always @(posedge clk) grcpeq1 <= (RAM_Y_value==CounterY); reg grcpeq2; always @(posedge clk) grcpeq2 <= grcpeq1; // check for "greater-than" between the "Y" values and "CounterY" reg grcp1; always @(posedge clk) grcp1 <= (RAM_Y_value>CounterY); reg grcp2; always @(posedge clk) grcp2 <= grcp1; // display a pixel if equality, or if "CounterY" is between 2 successive "Y" values wire FXpix= grcpeq2 | (grcp1 ^ grcp2); reg [15:0] X0, Y0, X1, Y1; always @(posedge clk) if(Vsync) begin X0 <= 0; Y0 <= 0; X1 <= 0; Y1 <= 0; end else if(Hsync) begin X0 <= X1 - 100; Y0 <= Y1 + 400; X1 <= X1 - 100; Y1 <= Y1 + 400; end else begin X0 <= X0 + 400; Y0 <= Y0 + 100; end // Display a chessboard pattern by XOR'ing the MSB of X and Y counters // You could also display a rotozoomed bitmap by feeding X and Y to a bitmap in a RAM wire rotozoom_pix = X0[15] ^ Y0[15]; #### 在图形LCD上显示文本信息 wire [7:0] CharacterRAM_dout; ram8x2048 CharacterRAM( .clk(clk), .rd_adr({CounterY[7:3],CounterX[6:1]}), .data_out(CharacterRAM_dout) ); wire [7:0] raster8; rom8x2048 FontROM( .clk(clk), .rd_adr({CharacterRAM_dout, CounterY[2:0]}), .data_out(raster8) ); wire [3:0] LCDdata = CounterX[0] ? raster8[7:4] : raster8[3:0]; wire [3:0] charfont0, charfont1; always @(posedge clk) begin case(cnt_mod3) 2'b00: LCDdata <= charfont0; 2'b01: LCDdata <= {charfont0[3:2], charfont1[3:2]}; 2'b10: LCDdata <= {charfont1[3:2], charfont0[1:0]}; endcase end reg [1:0] cnt_mod3; always @(posedge clk) if(cnt_mod3==2) cnt_mod3 <= 0; else cnt_mod3 <= cnt_mod3 + 1; // character-counter (increments only twice every 3 clocks) reg [6:0] cnt_charbuf; always @(posedge clk) if(cnt_mod3!=1) cnt_charbuf <= cnt_charbuf + 1; wire [11:0] CharacterRAM_rdaddr = CounterY[8:3]*80 + cnt_charbuf; wire [7:0] CharacterRAM_dout; ram8x2048 CharacterRAM( .clk(clk), .rd_adr(CharacterRAM_rdaddr), .data_out(CharacterRAM_dout) ); // remember the previous character displayed reg [7:0] RAM_charbuf_dout_last; always @(posedge clk) CharacterRAM_dout_last <= CharacterRAM_dout; // because we need it when we display 2 half characters at once wire [10:0] readaddr0 = {CharacterRAM_dout, CounterY[2:0]}; wire [10:0] readaddr1 = {CharacterRAM_dout_last, CounterY[2:0]}; // The font ROMs are split in two blockrams, holding 4 pixels each // (half of the second ROM is not used, since we need only 6 pixels) rom4x2048 FontROM0(.clk(clk), .rd_adr(readaddr0), .data_out(charfont0)); rom4x2048 FontROM1(.clk(clk), .rd_adr(readaddr1), .data_out(charfont1)); reg [5:0] cnt_cursorblink; always @(posedge clk) if(vsync & hsync) cnt_cursorblink <= cnt_cursorblink + 1; wire cursorblinkstate = cnt_cursorblink[5]; // cursor on for 32 frames, off for 32 frames // Do we have a cursor-character match? wire cursorblink_adrmatch = cursorblinkstate & (CharacterRAM_rdaddr==CursorAddress); // When we have a match, "invert" the character // First for charfont0 wire [3:0] charfont0_cursor = charfont0 ^ {4{cursorblink_adrmatch}}; // Next for charfont1 reg cursorblink_adrmatch_last; always @(posedge clk) cursorblink_adrmatch_last <= cursorblink_adrmatch; wire [3:0] charfont1_cursor = charfont1 ^ {4{cursorblink_adrmatch_last}};