diff options
Diffstat (limited to 'display.v')
-rw-r--r-- | display.v | 245 |
1 files changed, 140 insertions, 105 deletions
@@ -1,18 +1,20 @@ module display ( - input clk, // 18.75 MHz - + input clk, // 18.75 MHz + input width, input reverse, input noblink, input testpattern, input reveal, - + output reg [10:0] a, input [7:0] d, output [10:0] ga, input [5:0] gd, + output [12:0] bga, + input [5:0] bgd, - output reg [2:0] rgb, + output reg [5:0] rgb, output vsync, output hsync, @@ -38,7 +40,7 @@ module display ( // 30 pixels ( 5 char) front porch // ---------- // 594 pixels (31.68 us) -// +// // Vertical: // 480 lines graphics (24 rows x 10 pixels x 2 scans/pixel) // 10 lines back porch/border @@ -59,101 +61,108 @@ module display ( // especially the desired aspect ratio. Therefore, we want to use -hsync // and -vsync, - meaning active low, + meaning active high. - parameter x_blank = 480+6; - parameter x_sync = x_blank+(12-6); - parameter x_front = x_sync+72; - parameter x_max = 594; - - parameter y_blank = 480; - parameter y_sync = y_blank+10; - parameter y_front = y_sync+2; - parameter y_max = 525; - - parameter hsync_minus = 1'b1; // -hsync - parameter vsync_minus = 1'b1; // -vsync - - reg hsync_q; // Horizontal sync active - reg vsync_q; // Vertical sync active - - reg [9:0] x; // Horizontal pixel count - reg [9:0] y; // Vertical pixel count - reg [6:0] xchr; // Character column (0..99) - reg [2:0] xpxl; // Pixel column in character (0..5) - reg [4:0] ychr; // Character row (0..26) - reg [3:0] ypxl; // Pixel row in character (0..9) - reg [4:0] ylu; // Previous character line - - wire xvideo; // Non-blanked in the x direction - wire yvideo; // Non-blanked in the y direction - wire [10:0] a80; // Memory address assuming 80 columns - wire [10:0] a80u; // Memory address assuming 80 columns (-1 line) - wire [10:0] a40; // Memory address assuming 40 columns - wire [10:0] a40u; // Memory address assuming 40 columns (-1 line) - reg [4:0] scan_counter; // Counter of total scans (for flashing et al) - reg [5:0] pixrow; // One character worth of pixels - reg prefetch; // True for the prefetch character position + parameter x_blank = 480+6; + parameter x_sync = x_blank+(12-6); + parameter x_front = x_sync+72; + parameter x_max = 594; + + parameter y_blank = 480; + parameter y_sync = y_blank+10; + parameter y_front = y_sync+2; + parameter y_max = 525; + + parameter hsync_minus = 1'b1; // -hsync + parameter vsync_minus = 1'b1; // -vsync + + reg hsync_q; // Horizontal sync active + reg vsync_q; // Vertical sync active + + reg [9:0] x; // Horizontal pixel count + reg [9:0] y; // Vertical pixel count + reg [6:0] xchr; // Character column (0..99) + reg [2:0] xpxl; // Pixel column in character (0..5) + reg [4:0] ychr; // Character row (0..26) + reg [3:0] ypxl; // Pixel row in character (0..9) + wire [3:0] ypxlp = ypxl + 4'd1; // d:o but 1..10 + reg [4:0] ylu; // Previous character line + + wire xvideo; // Non-blanked in the x direction + wire yvideo; // Non-blanked in the y direction + wire [10:0] a80; // Memory address assuming 80 columns + wire [10:0] a80u; // Memory address assuming 80 columns (-1 line) + wire [10:0] a40; // Memory address assuming 40 columns + wire [10:0] a40u; // Memory address assuming 40 columns (-1 line) + reg [4:0] scan_counter; // Counter of total scans (for flashing et al) + reg [5:0] pixrow; // One character worth of pixels + reg prefetch; // True for the prefetch character position // Fine Graphics control - reg [7:0] fgctl_q; // Latched version of fg_ctl - reg [7:0] fgpixels; // One byte of fg pixels - + reg [7:0] fgctl_q; // Latched version of fg_ctl + reg [7:0] fgpixels; // One byte of fg pixels + + // Block graphics data + reg [5:0] block_rgb; // Current block graphics pixel + reg [6:0] block_x; // Block graphics pixel X + reg [2:0] block_xpxl; // Physical pixel inside block + // We leverage ychr and ypxl for the vertical + // For the current text line - reg [2:0] curfg; // Foreground RGB - reg [2:0] curbg; // Background RGB - reg inverse; // Inverse video - reg isgraph; // Graphic mode? - reg isgsep; // Separated graphics? - reg isgrel; // Hold graphics? - reg isdble; // Double height? - reg isflsh; // Flashing? - reg ishide; // Hidden - reg [7:0] thischar; // Character code currently processing + reg [2:0] curfg; // Foreground RGB + reg [2:0] curbg; // Background RGB + reg inverse; // Inverse video + reg isgraph; // Graphic mode? + reg isgsep; // Separated graphics? + reg isgrel; // Hold graphics? + reg isdble; // Double height? + reg isflsh; // Flashing? + reg ishide; // Hidden + reg [7:0] thischar; // Character code currently processing // These refer to the same as above, but for the previous text line - reg [2:0] oldfg; // Foreground RGB - reg [2:0] oldbg; // Background RGB - reg wasgraph; // Graphic mode? - reg wasgsep; // Separated graphics? - reg wasgrel; // Hold graphics? - reg wasdble; // Double height? - reg wasflsh; // Flashing? - reg washide; // Hidden - reg [7:0] thatchar; // Character code currently processing + reg [2:0] oldfg; // Foreground RGB + reg [2:0] oldbg; // Background RGB + reg wasgraph; // Graphic mode? + reg wasgsep; // Separated graphics? + reg wasgrel; // Hold graphics? + reg wasdble; // Double height? + reg wasflsh; // Flashing? + reg washide; // Hidden + reg [7:0] thatchar; // Character code currently processing // The one we're currently displaying - wire [2:0] fg = wasdble ? oldfg : curfg; - wire [2:0] bg = wasdble ? oldbg : curbg; - wire [7:0] somechar = wasdble ? thatchar : thischar; + wire [2:0] fg = wasdble ? oldfg : curfg; + wire [2:0] bg = wasdble ? oldbg : curbg; + wire [7:0] somechar = wasdble ? thatchar : thischar; wire gsep = wasdble ? wasgsep : isgsep; - wire do_flsh = wasdble ? wasflsh : isflsh; - wire do_hide = wasdble ? washide : ishide; + wire do_flsh = wasdble ? wasflsh : isflsh; + wire do_hide = wasdble ? washide : ishide; // Should we advance the character pixel? // We need to always advance at full speed during prefetch, or // we would have to start the prefetch earlier in 40-character mode. - wire advance = width | x[0] | prefetch; - + wire advance = width | x[0] | prefetch; + // Address mapping for 40 and 80 characters - assign a80[3:0] = xchr[3:0]; - wire [3:0] x80middle = { 1'b0, xchr[6:4] }; - wire [3:0] ymiddle = { ychr[4:3] , ychr[4:3] }; - assign a80[7:4] = x80middle+ymiddle; - assign a80[10:8] = ychr[2:0]; + assign a80[3:0] = xchr[3:0]; + wire [3:0] x80middle = { 1'b0, xchr[6:4] }; + wire [3:0] ymiddle = { ychr[4:3] , ychr[4:3] }; + assign a80[7:4] = x80middle+ymiddle; + assign a80[10:8] = ychr[2:0]; assign a40[2:0] = xchr[2:0]; - wire [3:0] x40middle = { 1'b0, xchr[5:3] }; - assign a40[6:3] = x40middle + ymiddle; - assign a40[10:7] = { 1'b1, ychr[2:0] }; + wire [3:0] x40middle = { 1'b0, xchr[5:3] }; + assign a40[6:3] = x40middle + ymiddle; + assign a40[10:7] = { 1'b1, ychr[2:0] }; // Address mapping for 40 and 80 characters minus one line - assign a80u[3:0] = xchr[3:0]; - wire [3:0] yumiddle = { ylu[4:3] , ylu[4:3] }; - assign a80u[7:4] = x80middle+yumiddle; - assign a80u[10:8] = ylu[2:0]; + assign a80u[3:0] = xchr[3:0]; + wire [3:0] yumiddle = { ylu[4:3] , ylu[4:3] }; + assign a80u[7:4] = x80middle+yumiddle; + assign a80u[10:8] = ylu[2:0]; - assign a40u[2:0] = xchr[2:0]; - assign a40u[6:3] = x40middle+yumiddle; - assign a40u[10:7] = { 1'b1, ylu[2:0] }; + assign a40u[2:0] = xchr[2:0]; + assign a40u[6:3] = x40middle+yumiddle; + assign a40u[10:7] = { 1'b1, ylu[2:0] }; // Final address mapping // Note: We read the current char between pixels 0 and 1, @@ -170,35 +179,42 @@ module display ( a = a80u; endcase // case( { width, xchr[1] } ) + // Block graphics address mapping + assign bga[3:0] = block_x[3:0]; + wire [3:0] bgxmiddle = { 1'b0, block_x[6:4] }; + wire [3:0] bgymiddle = { ypxlp[3:2], ypxlp[3:2] }; + assign bga[7:4] = bgxmiddle + bgymiddle; + assign bga[12:8] = ychr; + // Character generator address mapping - assign ga[10:4] = somechar[6:0]; - assign ga[3:0] = wasdble ? { 1'b1, ypxl[3:1] } : + assign ga[10:4] = somechar[6:0]; + assign ga[3:0] = wasdble ? { 1'b1, ypxl[3:1] } : isdble ? { 1'b0, ypxl[3:1] } : ypxl[3:0]; // Video enable signal - assign xvideo = ( x < x_blank ); - assign yvideo = ( y < y_blank ); + assign xvideo = ( x < x_blank ); + assign yvideo = ( y < y_blank ); + + assign hsync = hsync_q ^ hsync_minus; + assign vsync = vsync_q ^ vsync_minus; - assign hsync = hsync_q ^ hsync_minus; - assign vsync = vsync_q ^ vsync_minus; - // Flashing - wire flash_on = scan_counter[4]; + wire flash_on = scan_counter[4]; // Inverse video. The normal is a flashing inverse cursor, but // if "noblink" is asserted the cursor is steady inverted. If // "reverse" is asserted with invert everything *on top of that*... - wire invert = (inverse & (flash_on|noblink))^reverse; + wire invert = (inverse & (flash_on|noblink))^reverse; // // Fine graphics // - assign fg_ack = xvideo & yvideo & (x[2:0] == 3'b000); - assign fg_xrst = yvideo & hsync_q; - assign fg_yrst = vsync_q; + assign fg_ack = xvideo & yvideo & (x[2:0] == 3'b000); + assign fg_xrst = yvideo & hsync_q; + assign fg_yrst = vsync_q; - wire [3:0] fg_argb; + wire [3:0] fg_argb; always @(posedge clk) if ( ~yvideo ) // Only change mode during vertical blank @@ -215,35 +231,37 @@ module display ( .clock ( clk ), .q ( fg_argb ) ); - + // Synchronous logic always @(posedge clk) begin if ( ~xvideo | ~yvideo | prefetch ) - rgb <= 3'b000; // Blank + rgb <= 6'b000000; // Blank else if ( testpattern ) // Pixel test pattern for LCD monitor calibration - rgb <= {3{x[0] ^ y[0]}}; + rgb <= {6{x[0] ^ y[0]}} ^ {6{invert}}; else if ( ~fgctl_q[7] & pixrow[5] & ~(do_flsh & ~flash_on) & ~(do_hide & ~reveal) ) - rgb <= fg ^ {3{invert}}; + rgb <= {fg[2],fg[2],fg[1],fg[1],fg[0],fg[0]} ^ {6{invert}}; else if (fgctl_q[7] | fg_argb[3]) - rgb <= fg_argb[2:0]; + rgb <= {fg_argb[2],fg_argb[2],fg_argb[1],fg_argb[1],fg_argb[0],fg_argb[0]} ^ {6{invert}}; + else if (bg == 3'b000) + rgb <= block_rgb ^ {6{invert}}; else - rgb <= bg ^ {3{invert}}; + rgb <= {bg[2],bg[2],bg[1],bg[1],bg[0],bg[0]} ^ {6{invert}}; // Sync pulses vsync_q <= ( y >= y_sync && y < y_front ); hsync_q <= ( x >= x_sync && x < x_front ); - + // Rotating shift register; may be overridden by the below // The rotation is so that if we're in GHOL mode we already // have the previous value if ( advance ) pixrow <= { pixrow[4:0], pixrow[5] }; - + // This code is run 6 times per character; regardless of width if ( advance ) begin @@ -259,7 +277,7 @@ module display ( // Load and process previous-line character thatchar <= (ychr == 0) ? 8'h00 : d; end - + 3'b101: begin // Load a new pixel row? @@ -416,14 +434,22 @@ module display ( end // case: 3'b101 endcase // case( xpxl ) end // if ( advance ) - + + // Block graphics - the block graphics pixels exactly match + // 80-column characters + if ( block_xpxl == 3'd5 ) + block_rgb <= bgd; + // Counters if ( x == x_max-1 ) begin x <= 10'd0; xchr <= 7'd0; xpxl <= 3'd0; + block_x <= 7'd0; + block_xpxl <= 3'd0; pixrow <= 6'b0; // Read-ahead spot is blank + block_rgb <= 6'b0; prefetch <= 1'b1; // Prefetch character inverse <= 1'b0; // Not inverse video curfg <= 3'b111; // Default fg is white @@ -477,6 +503,15 @@ module display ( else xpxl <= xpxl + 1; end + + if ( block_xpxl == 3'd5 ) + begin + block_xpxl <= 0; + block_x <= block_x + 1; + end + else + block_xpxl <= block_xpxl + 1; + x <= x + 1; end // else: !if( x == x_max-1 ) end // always @ (posedge clk) |