From 2798fb223a8fd2b8fd408cc120279909b9d1b5fd Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Sat, 27 Jun 2015 12:05:33 -0700 Subject: [PATCH] More VGA tests --- tests/pc/vga/L26-1.ASM | 293 +++++++++++++++++++++++++++++++++++++ tests/pc/vga/L26-2.ASM | 318 +++++++++++++++++++++++++++++++++++++++++ tests/pc/vga/README.md | 3 + 3 files changed, 614 insertions(+) create mode 100644 tests/pc/vga/L26-1.ASM create mode 100644 tests/pc/vga/L26-2.ASM diff --git a/tests/pc/vga/L26-1.ASM b/tests/pc/vga/L26-1.ASM new file mode 100644 index 000000000..790eaf10b --- /dev/null +++ b/tests/pc/vga/L26-1.ASM @@ -0,0 +1,293 @@ +; Program to illustrate operation of write mode 3 of the VGA. +; Draws 8x8 characters at arbitrary locations without disturbing +; the background, using VGA's 8x8 ROM font. Designed +; for use with modes 0Dh, 0Eh, 0Fh, 10h, and 12h. +; Runs only on VGAs (in Models 50 & up and IBM Display Adapter +; and 100% compatibles). +; Assembled with MASM +; By Michael Abrash +; +stack segment para stack 'STACK' + db 512 dup(?) +stack ends +; +VGA_VIDEO_SEGMENT equ 0a000h ;VGA display memory segment +SCREEN_WIDTH_IN_BYTES equ 044ah ;offset of BIOS variable +FONT_CHARACTER_SIZE equ 8 ;# bytes in each font char +; +; VGA register equates. +; +SC_INDEX equ 3c4h ;SC index register +SC_MAP_MASK equ 2 ;SC map mask register index +GC_INDEX equ 3ceh ;GC index register +GC_SET_RESET equ 0 ;GC set/reset register index +GC_ENABLE_SET_RESET equ 1 ;GC enable set/reset register index +GC_ROTATE equ 3 ;GC data rotate/logical function + ; register index +GC_MODE equ 5 ;GC Mode register +GC_BIT_MASK equ 8 ;GC bit mask register index +; +dseg segment para common 'DATA' +TEST_TEXT_ROW equ 69 ;row to display test text at +TEST_TEXT_COL equ 17 ;column to display test text at +TEST_TEXT_WIDTH equ 8 ;width of a character in pixels +TestString label byte + db 'Hello, world!',0 ;test string to print. +FontPointer dd ? ;font offset +dseg ends +; +cseg segment para public 'CODE' + assume cs:cseg, ds:dseg +start proc near + mov ax,dseg + mov ds,ax +; +; Select 640x480 graphics mode. +; + mov ax,012h + int 10h +; +; Set the screen to all blue, using the readability of VGA registers +; to preserve reserved bits. +; + mov dx,GC_INDEX + mov al,GC_SET_RESET + out dx,al + inc dx + in al,dx + and al,0f0h + or al,1 ;blue plane only set, others reset + out dx,al + dec dx + mov al,GC_ENABLE_SET_RESET + out dx,al + inc dx + in al,dx + and al,0f0h + or al,0fh ;enable set/reset for all planes + out dx,al + mov dx,VGA_VIDEO_SEGMENT + mov es,dx ;point to display memory + mov di,0 + mov cx,8000h ;fill all 32k words + mov ax,0ffffh ;because of set/reset, the value + ; written actually doesn't matter + rep stosw ;fill with blue +; +; Set driver to use the 8x8 font. +; + mov ah,11h ;VGA BIOS character generator function, + mov al,30h ; return info subfunction + mov bh,3 ;get 8x8 font pointer + int 10h + call SelectFont +; +; Print the test string, cycling through colors. +; + mov si,offset TestString + mov bx,TEST_TEXT_ROW + mov cx,TEST_TEXT_COL + mov ah,0 ;start with color 0 +StringOutLoop: + lodsb + and al,al + jz StringOutDone + push ax ;preserve color + call DrawChar + pop ax ;restore color + inc ah ;next color + and ah,0fh ;colors range from 0 to 15 + add cx,TEST_TEXT_WIDTH + jmp StringOutLoop +StringOutDone: +; +; Wait for a key, then set to text mode & end. +; + mov ah,1 + int 21h ;wait for a key + mov ax,3 + int 10h ;restore text mode +; +; Exit to DOS. +; + mov ah,4ch + int 21h +Start endp +; +; Subroutine to draw a text character in a linear graphics mode +; (0Dh, 0Eh, 0Fh, 010h, 012h). Background around the pixels that +; make up the character is preserved. +; Font used should be pointed to by FontPointer. +; +; Input: +; AL = character to draw +; AH = color to draw character in (0-15) +; BX = row to draw text character at +; CX = column to draw text character at +; +; Forces ALU function to "move". +; Forces write mode 3. +; +DrawChar proc near + push ax + push bx + push cx + push dx + push si + push di + push bp + push ds + push ax ;preserve character to draw in AL +; +; Set up set/reset to produce character color, using the readability +; of VGA register to preserve the setting of reserved bits 7-4. +; + mov dx,GC_INDEX + mov al,GC_SET_RESET + out dx,al + inc dx + in al,dx + and al,0f0h + and ah,0fh + or al,ah + out dx,al +; +; Select write mode 3, using the readability of VGA registers +; to leave bits other than the write mode bits unchanged. +; + mov dx,GC_INDEX + mov al,GC_MODE + out dx,al + inc dx + in al,dx + or al,3 + out dx,al +; +; Set DS:SI to point to font and ES to point to display memory. +; + lds si,[FontPointer] ;point to font + mov dx,VGA_VIDEO_SEGMENT + mov es,dx ;point to display memory +; +; Calculate screen address of byte character starts in. +; + pop ax ;get back character to draw in AL + + push ds ;point to BIOS data segment + sub dx,dx + mov ds,dx + xchg ax,bx + mov di,ds:[SCREEN_WIDTH_IN_BYTES] ;retrieve BIOS + ; screen width + pop ds + mul di ;calculate offset of start of row + push di ;set aside screen width + mov di,cx ;set aside the column + and cl,0111b ;keep only the column in-byte address + shr di,1 + shr di,1 + shr di,1 ;divide column by 8 to make a byte address + add di,ax ;and point to byte +; +; Calculate font address of character. +; + sub bh,bh + shl bx,1 ;assumes 8 bytes per character; use + shl bx,1 ; a multiply otherwise + shl bx,1 ;offset in font of character + add si,bx ;offset in font segment of character +; +; Set up the GC rotation. In write mode 3, this is the rotation +; of CPU data before it is ANDed with the Bit Mask register to +; form the bit mask. Force the ALU function to "move". Uses the +; readability of VGA registers to leave reserved bits unchanged. +; + mov dx,GC_INDEX + mov al,GC_ROTATE + out dx,al + inc dx + in al,dx + and al,0e0h + or al,cl + out dx,al +; +; Set up BH as bit mask for left half, BL as rotation for right half. +; + mov bx,0ffffh + shr bh,cl + neg cl + add cl,8 + shl bl,cl +; +; Draw the character, left half first, then right half in the +; succeeding byte, using the data rotation to position the character +; across the byte boundary and then using write mode 3 to combine the +; character data with the bit mask to allow the set/reset value (the +; character color) through only for the proper portion (where the +; font bits for the character are 1) of the character for each byte. +; Wherever the font bits for the character are 0, the background +; color is preserved. +; Does not check for case where character is byte-aligned and +; no rotation and only one write is required. +; + mov bp,FONT_CHARACTER_SIZE + mov dx,GC_INDEX + pop cx ;get back screen width + dec cx + dec cx ; -2 because do two bytes for each char +CharacterLoop: +; +; Set the bit mask for the left half of the character. +; + mov al,GC_BIT_MASK + mov ah,bh + out dx,ax +; +; Get the next character byte & write it to display memory. +; (Left half of character.) +; + mov al,[si] ;get character byte + mov ah,es:[di] ;load latches + stosb ;write character byte +; +; Set the bit mask for the right half of the character. +; + mov al,GC_BIT_MASK + mov ah,bl + out dx,ax +; +; Get the character byte again & write it to display memory. +; (Right half of character.) +; + lodsb ;get character byte + mov ah,es:[di] ;load latches + stosb ;write character byte +; +; Point to next line of character in display memory. +; + add di,cx +; + dec bp + jnz CharacterLoop +; + pop ds + pop bp + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret +DrawChar endp +; +; Set the pointer to the font to draw from to ES:BP. +; +SelectFont proc near + mov word ptr [FontPointer],bp ;save pointer + mov word ptr [FontPointer+2],es + ret +SelectFont endp +; +cseg ends + end start diff --git a/tests/pc/vga/L26-2.ASM b/tests/pc/vga/L26-2.ASM new file mode 100644 index 000000000..eeb871537 --- /dev/null +++ b/tests/pc/vga/L26-2.ASM @@ -0,0 +1,318 @@ +; Program to illustrate high-speed text-drawing operation of +; write mode 3 of the VGA. +; Draws a string of 8x14 characters at arbitrary locations +; without disturbing the background, using VGA's 8x14 ROM font. +; Designed for use with modes 0Dh, 0Eh, 0Fh, 10h, and 12h. +; Runs only on VGAs (in Models 50 & up and IBM Display Adapter +; and 100% compatibles). +; Assembled with MASM +; By Michael Abrash +; +stack segment para stack 'STACK' + db 512 dup(?) +stack ends +; +VGA_VIDEO_SEGMENT equ 0a000h ;VGA display memory segment +SCREEN_WIDTH_IN_BYTES equ 044ah ;offset of BIOS variable +FONT_CHARACTER_SIZE equ 14 ;# bytes in each font char +; +; VGA register equates. +; +SC_INDEX equ 3c4h ;SC index register +SC_MAP_MASK equ 2 ;SC map mask register index +GC_INDEX equ 3ceh ;GC index register +GC_SET_RESET equ 0 ;GC set/reset register index +GC_ENABLE_SET_RESET equ 1 ;GC enable set/reset register index +GC_ROTATE equ 3 ;GC data rotate/logical function + ; register index +GC_MODE equ 5 ;GC Mode register +GC_BIT_MASK equ 8 ;GC bit mask register index +; +dseg segment para common 'DATA' +TEST_TEXT_ROW equ 69 ;row to display test text at +TEST_TEXT_COL equ 17 ;column to display test text at +TEST_TEXT_COLOR equ 0fh ;high intensity white +TestString label byte + db 'Hello, world!',0 ;test string to print. +FontPointer dd ? ;font offset +dseg ends +; +cseg segment para public 'CODE' + assume cs:cseg, ds:dseg +start proc near + mov ax,dseg + mov ds,ax +; +; Select 640x480 graphics mode. +; + mov ax,012h + int 10h +; +; Set the screen to all blue, using the readability of VGA registers +; to preserve reserved bits. +; + mov dx,GC_INDEX + mov al,GC_SET_RESET + out dx,al + inc dx + in al,dx + and al,0f0h + or al,1 ;blue plane only set, others reset + out dx,al + dec dx + mov al,GC_ENABLE_SET_RESET + out dx,al + inc dx + in al,dx + and al,0f0h + or al,0fh ;enable set/reset for all planes + out dx,al + mov dx,VGA_VIDEO_SEGMENT + mov es,dx ;point to display memory + mov di,0 + mov cx,8000h ;fill all 32k words + mov ax,0ffffh ;because of set/reset, the value + ; written actually doesn't matter + rep stosw ;fill with blue +; +; Set driver to use the 8x14 font. +; + mov ah,11h ;VGA BIOS character generator function, + mov al,30h ; return info subfunction + mov bh,2 ;get 8x14 font pointer + int 10h + call SelectFont +; +; Print the test string. +; + mov si,offset TestString + mov bx,TEST_TEXT_ROW + mov cx,TEST_TEXT_COL + mov ah,TEST_TEXT_COLOR + call DrawString +; +; Wait for a key, then set to text mode & end. +; + mov ah,1 + int 21h ;wait for a key + mov ax,3 + int 10h ;restore text mode +; +; Exit to DOS. +; + mov ah,4ch + int 21h +Start endp +; +; Subroutine to draw a text string left-to-right in a linear +; graphics mode (0Dh, 0Eh, 0Fh, 010h, 012h) with 8-dot-wide +; characters. Background around the pixels that make up the +; characters is preserved. +; Font used should be pointed to by FontPointer. +; +; Input: +; AH = color to draw string in +; BX = row to draw string on +; CX = column to start string at +; DS:SI = string to draw +; +; Forces ALU function to "move". +; Forces write mode 3. +; +DrawString proc near + push ax + push bx + push cx + push dx + push si + push di + push bp + push ds +; +; Set up set/reset to produce character color, using the readability +; of VGA register to preserve the setting of reserved bits 7-4. +; + mov dx,GC_INDEX + mov al,GC_SET_RESET + out dx,al + inc dx + in al,dx + and al,0f0h + and ah,0fh + or al,ah + out dx,al +; +; Select write mode 3, using the readability of VGA registers +; to leave bits other than the write mode bits unchanged. +; + mov dx,GC_INDEX + mov al,GC_MODE + out dx,al + inc dx + in al,dx + or al,3 + out dx,al + mov dx,VGA_VIDEO_SEGMENT + mov es,dx ;point to display memory +; +; Calculate screen address of byte character starts in. +; + push ds ;point to BIOS data segment + sub dx,dx + mov ds,dx + mov di,ds:[SCREEN_WIDTH_IN_BYTES] ;retrieve BIOS + ; screen width + pop ds + mov ax,bx ;row + mul di ;calculate offset of start of row + push di ;set aside screen width + mov di,cx ;set aside the column + and cl,0111b ;keep only the column in-byte address + shr di,1 + shr di,1 + shr di,1 ;divide column by 8 to make a byte address + add di,ax ;and point to byte +; +; Set up the GC rotation. In write mode 3, this is the rotation +; of CPU data before it is ANDed with the Bit Mask register to +; form the bit mask. Force the ALU function to "move". Uses the +; readability of VGA registers to leave reserved bits unchanged. +; + mov dx,GC_INDEX + mov al,GC_ROTATE + out dx,al + inc dx + in al,dx + and al,0e0h + or al,cl + out dx,al +; +; Set up BH as bit mask for left half, BL as rotation for right half. +; + mov bx,0ffffh + shr bh,cl + neg cl + add cl,8 + shl bl,cl +; +; Draw all characters, left portion first, then right portion in the +; succeeding byte, using the data rotation to position the character +; across the byte boundary and then using write mode 3 to combine the +; character data with the bit mask to allow the set/reset value (the +; character color) through only for the proper portion (where the +; font bits for the character are 1) of the character for each byte. +; Wherever the font bits for the character are 0, the background +; color is preserved. +; Does not check for case where character is byte-aligned and +; no rotation and only one write is required. +; +; Draw the left portion of each character in the string. +; + pop cx ;get back screen width + push si + push di + push bx +; +; Set the bit mask for the left half of the character. +; + mov dx,GC_INDEX + mov al,GC_BIT_MASK + mov ah,bh + out dx,ax +LeftHalfLoop: + lodsb + and al,al + jz LeftHalfLoopDone + call CharacterUp + inc di ;point to next character location + jmp LeftHalfLoop +LeftHalfLoopDone: + pop bx + pop di + pop si +; +; Draw the right portion of each character in the string. +; + inc di ;right portion of each character is across + ; byte boundary +; +; Set the bit mask for the right half of the character. +; + mov dx,GC_INDEX + mov al,GC_BIT_MASK + mov ah,bl + out dx,ax +RightHalfLoop: + lodsb + and al,al + jz RightHalfLoopDone + call CharacterUp + inc di ;point to next character location + jmp RightHalfLoop +RightHalfLoopDone: +; + pop ds + pop bp + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret +DrawString endp +; +; Draw a character. +; +; Input: +; AL = character +; CX = screen width +; ES:DI = address to draw character at +; +CharacterUp proc near + push cx + push si + push di + push ds +; +; Set DS:SI to point to font and ES to point to display memory. +; + lds si,[FontPointer] ;point to font +; +; Calculate font address of character. +; + mov bl,14 ;14 bytes per character + mul bl + add si,ax ;offset in font segment of character + + mov bp,FONT_CHARACTER_SIZE + dec cx ; -1 because one byte per char +CharacterLoop: + lodsb ;get character byte + mov ah,es:[di] ;load latches + stosb ;write character byte +; +; Point to next line of character in display memory. +; + add di,cx +; + dec bp + jnz CharacterLoop +; + pop ds + pop di + pop si + pop cx + ret +CharacterUp endp +; +; Set the pointer to the font to draw from to ES:BP. +; +SelectFont proc near + mov word ptr [FontPointer],bp ;save pointer + mov word ptr [FontPointer+2],es + ret +SelectFont endp +; +cseg ends + end start diff --git a/tests/pc/vga/README.md b/tests/pc/vga/README.md index 195478a3b..5aa082f0c 100644 --- a/tests/pc/vga/README.md +++ b/tests/pc/vga/README.md @@ -34,6 +34,9 @@ List of VGA Samples from [Michael Abrash's Graphics Programming Black Book](http * [L25-2.ASM: Illustrates operation of Map Mask register when drawing to memory that already contains data](L25-2.ASM) * [L25-3.ASM: Illustrates operation of set/reset circuitry to force setting of memory that already contains data](L25-3.ASM) * [L25-4.ASM: Illustrates operation of set/reset circuitry in conjunction with CPU data](L25-4.ASM) + * [Chapter 26](https://github.com/jeffpar/abrash-black-book/blob/master/src/chapter-26.md) + * [L26-1.ASM: Illustrates operation of write mode 3 of the VGA](L26-1.ASM) + * [L26-2.ASM: Illustrates high-speed text-drawing operation of write mode 3 of the VGA](L26-2.ASM) ---