// // File: vga_textgrid22x.v // Date: 03-Dec-05 // Author: I. Chuang // // VGA display of characters in a grid. // // Display both 12x24 and 2x pixel 12x24 characters on 640x480 display // using one shared global font rom. // // The display is assumed to be 640x480, such that for 12x24 // characters, we get a 53x20 display. `include "font1224_rom.v" module vga_textgrid22x ( input wire vclock, // system synchronous clock input wire pix_clk, // video pixel clock input wire [9:0] hcount, // current hpos (0..639) input wire [9:0] vcount, // current vpos (0..479) output wire [2:0] pixel, // pixel output output wire [5:0] cx, // next char pos output wire [5:0] cy, // next char pos output wire adv_cclk, // early character clock input wire [10:0] charrgb, // char+rgb to display at pos output wire [5:0] cx2, // next 2x char pos output wire [5:0] cy2, // next 2x char pos output wire adv_cclk2, // early 2x char clock input wire [10:0] charrgb2 // 2x char+rgb ); // global font rom wire [11:0] font_byte; // each word has 12 bits wire [12:0] font_addr; font1224_rom fr(font_addr, vclock, font_byte); // font rom // normal size (1x) character display wire [2:0] pix1; wire [12:0] font_addr1; vga_textgrid2x vtg1(vclock, pix_clk, hcount, vcount, pix1, cx, cy, adv_cclk, charrgb[7:0], charrgb[10:8], font_addr1, font_byte); // big (2x) character display wire [2:0] pix2; wire [12:0] font_addr2; vga_textgrid2x vtg2(vclock, pix_clk, hcount, vcount, pix2, cx2, cy2, adv_cclk2, charrgb2[7:0], charrgb2[10:8], font_addr2, font_byte); defparam vtg2.MAG = 1; // share font rom by or'ing addresses together assign font_addr = font_addr1 | font_addr2; // generate combined pixel by OR'ing assign pixel = pix1 | pix2; endmodule // vga_textgrid22x ///////////////////////////////////////////////////////////////////////////// module vga_textgrid2x ( input wire vclock, // system synchronous clock input wire pix_clk, // video pixel clock input wire [9:0] hcount, // current hpos (0..639) input wire [9:0] vcount, // current vpos (0..479) output reg [2:0] pixel, // pixel output output reg [5:0] cx, // next char pos output reg [5:0] cy, // next char pos output reg adv_cclk, // early character clock input wire [7:0] char, // char to display at pos input wire [2:0] rgb, // RGB to output for char output wire [12:0] font_addr, // font rom address input wire [11:0] font_byte // font rom read data ); parameter MAG = 0; // 1 for 2X chars parameter HMAX = 12*(MAG+1); // # x-pixels in char (24 for 2x chars) parameter VMAX = 24*(MAG+1); // # y-pixels in char (48 for 2x chars) parameter CXMAX = 26*(2-MAG); // # of chars in row (26 for 2X chars) // compute character clock (cclk) and h,v position within character reg [4:0] h; // 0 .. 23 or 0 .. 11 reg [5:0] v; // 0 .. 47 or 0 .. 23 reg [5:0] vnext; // in-char v position for _next_ char // wire hzero = (hcount>=679 | h==0); wire hzero = (hcount==0 | h==0); wire vzero = (vcount==0 | v==(VMAX-1)); wire hhalf = (h==3); // early char clk (external world) reg old_hzero, old_hhalf; reg cclk; // actual character clk (when vid char changes) wire indisp = (hcount<624) & (vcount<480); always @(posedge vclock) begin cclk <= hzero & ~old_hzero & indisp; // one pulse each time h==0 old_hzero <= hzero; adv_cclk <= hhalf & ~old_hhalf & indisp; // get char index in advance old_hhalf <= hhalf; if (~pix_clk) begin h <= hzero ? (HMAX-1) : h-1; v <= (~(hcount==0)) ? v : (vzero ? 0 : v+1); vnext <= (hcount==679) ? (vzero ? 0 : vnext+1) : vnext; end end // compute next character position based on current hpos, vpos wire eol = (hcount>=((CXMAX-1)*HMAX)); always @(posedge vclock) if (cclk) begin cx <= eol ? 0 : cx+1; cy <= (cx==(CXMAX-1) & v==(VMAX-1)) ? ( (vcount>=456) ? 0 : cy+1 ) : cy; end // look up raster row from font rom: 24 words per character // if char=0 then font_addr = 0 (so we can share the rom) wire reverse = char[7]; assign font_addr = (|{char}) ? char[6:0]*24 + vnext[4+MAG:0+MAG]-24 : 13'b0; // assign [11:0] font_byte; // each word has 12 bits // font1224_rom fr(font_addr, vclock, font_byte); // font rom // latch output of font rom when character clock (cclk) is high // and generate character pixel reg [11:0] fb_latched; reg nochar; reg rev_latched; reg [2:0] rgb_latched; always @(posedge vclock) if (cclk) begin fb_latched <= font_byte; nochar <= (char==0); rev_latched <= reverse; rgb_latched <= rgb; end // wire [2:0] cpixel = ( (nochar|~indisp) ? 3'b0 // : (fb_latched[h[3+MAG:0+MAG]] ^ reverse) ? rgb // : 3'b0 ); reg [2:0] cpixel; always @(posedge vclock) if (pix_clk) cpixel <= ( (nochar|~indisp) ? 3'b0 : (fb_latched[h[3+MAG:0+MAG]] ^ rev_latched) ? rgb_latched : 3'b0 ); // latch in pixel, and don't change except on pix_clk always @(posedge vclock) pixel <= (pix_clk & indisp) ? cpixel : pixel; endmodule //////////////////////////////////////// // vga_dispstr: Display a single text string, given as a parameter // to the module. module vga_dispstr( input wire clk, input wire cclk, input wire [5:0] x, input wire [5:0] y, input wire [5:0] cx, input wire [5:0] cy, output reg [10:0] charrgb ); parameter TEXT = "TEST"; parameter LEN = 4; parameter RGB = 3'b111; reg [LEN*8-1:0] sr; wire dispflag = (cy==y) & (cx>=x) & (cx<(x+LEN)); // reg [7:0] q; always @(posedge clk) if (cclk) begin // char <= dispflag ? "T" : 8'b0; charrgb <= dispflag ? {RGB,sr[LEN*8-1:LEN*8-8]} : 8'b0; sr <= dispflag ? {sr[LEN*8-9:0],8'b0} : TEXT; // char <= dispflag ? q : 8'b0; // q <= dispflag ? q+1 : "0"; end endmodule // vga_dispstr //////////////////////////////////////// // hex2ascii module hex2ascii(input wire [3:0] hex, output wire [7:0] ascii); assign ascii = (hex<4'd10) ? (8'd48 + {4'b0,hex}) : (8'd65 + {4'b0,hex} - 4'd10); endmodule // hex2ascii //////////////////////////////////////// // vga_disphex: Display a string of hex digits module vga_disphex #( parameter ND = 4, parameter RGB = 3'b111 )( input wire clk, input wire cclk, input wire [5:0] x, input wire [5:0] y, input wire [5:0] cx, input wire [5:0] cy, input wire [ND*4-1:0] data, input wire [ND-1:0] rev, output reg [10:0] charrgb ); reg [ND*4-1+4:0] sr; // extra 4 bits on left handles when ND=1 reg [ND:0] rev_sr; wire dispflag = (cy==y) & (cx>=x) & (cx<(x+ND)); wire [7:0] ascii; hex2ascii h2a(sr[ND*4-1+4:ND*4],ascii); always @(posedge clk) if (cclk) begin charrgb <= dispflag ? {RGB,rev_sr[ND],ascii[6:0]} : 8'b0; sr <= (dispflag & (ND>1)) ? {sr[ND*4-1:0],4'b0} : {data,4'b0}; rev_sr <= (dispflag & (ND>1)) ? {rev_sr[ND-1:0],1'b0} : {rev,1'b0}; end endmodule // vga_disphex