diff --git a/tests/pc/vga/L27-1.ASM b/tests/pc/vga/L27-1.ASM new file mode 100644 index 000000000..c311c66e0 --- /dev/null +++ b/tests/pc/vga/L27-1.ASM @@ -0,0 +1,218 @@ +; Program to illustrate one use of write mode 2 of the VGA and EGA by +; animating the image of an "A" drawn by copying it from a chunky +; bit-map in system memory to a planar bit-map in VGA or EGA memory. +; +; Assemble with MASM or TASM +; +; By Michael Abrash +; +Stack segment para stack 'STACK' + db 512 dup(0) +Stack ends + +SCREEN_WIDTH_IN_BYTES equ 80 +DISPLAY_MEMORY_SEGMENT equ 0a000h + +SC_INDEX equ 3c4h ;Sequence Controller Index register +MAP_MASK equ 2 ;index of Map Mask register +GC_INDEX equ 03ceh ;Graphics Controller Index reg +GRAPHICS_MODE equ 5 ;index of Graphics Mode reg +BIT_MASK equ 8 ;index of Bit Mask reg + +Data segment para common 'DATA' +; +; Current location of "A" as it is animated across the screen. +; +CurrentX dw ? +CurrentY dw ? +RemainingLength dw ? +; +; Chunky bit-map image of a yellow "A" on a bright blue background +; +AImage label byte + dw 13, 13 ;width, height in pixels + db 000h, 000h, 000h, 000h, 000h, 000h, 000h + db 009h, 099h, 099h, 099h, 099h, 099h, 000h + db 009h, 099h, 099h, 099h, 099h, 099h, 000h + db 009h, 099h, 099h, 0e9h, 099h, 099h, 000h + db 009h, 099h, 09eh, 0eeh, 099h, 099h, 000h + db 009h, 099h, 0eeh, 09eh, 0e9h, 099h, 000h + db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h + db 009h, 09eh, 0eeh, 0eeh, 0eeh, 099h, 000h + db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h + db 009h, 09eh, 0e9h, 099h, 0eeh, 099h, 000h + db 009h, 099h, 099h, 099h, 099h, 099h, 000h + db 009h, 099h, 099h, 099h, 099h, 099h, 000h + db 000h, 000h, 000h, 000h, 000h, 000h, 000h +Data ends + +Code segment para public 'CODE' + assume cs:Code, ds:Data +Start proc near + mov ax,Data + mov ds,ax + mov ax,10h + int 10h ;select video mode 10h (640x350) +; +; Prepare for animation. +; + mov [CurrentX],0 + mov [CurrentY],200 + mov [RemainingLength],600 ;move 600 times +; +; Animate, repeating RemainingLength times. It's unnecessary to erase +; the old image, since the one pixel of blank fringe around the image +; erases the part of the old image not overlapped by the new image. +; +AnimationLoop: + mov bx,[CurrentX] + mov cx,[CurrentY] + mov si,offset AImage + call DrawFromChunkyBitmap ;draw the "A" image + inc [CurrentX] ;move one pixel to the right + + mov cx,0 ;delay so we don't move the +DelayLoop: ; image too fast; adjust as + ; needed + loop DelayLoop + + dec [RemainingLength] + jnz AnimationLoop +; +; Wait for a key before returning to text mode and ending. +; + mov ah,01h + int 21h + mov ax,03h + int 10h + mov ah,4ch + int 21h +Start endp +; +; Draw an image stored in a chunky-bit map into planar VGA/EGA memory +; at the specified location. +; +; Input: +; BX = X screen location at which to draw the upper-left corner +; of the image +; CX = Y screen location at which to draw the upper-left corner +; of the image +; DS:SI = pointer to chunky image to draw, as follows: +; word at 0: width of image, in pixels +; word at 2: height of image, in pixels +; byte at 4: msb/lsb = first & second chunky pixels, +; repeating for the remainder of the scan line +; of the image, then for all scan lines. Images +; with odd widths have an unused null nibble +; padding each scan line out to a byte width +; +; AX, BX, CX, DX, SI, DI, ES destroyed. +; +DrawFromChunkyBitmap proc near + cld +; +; Select write mode 2. +; + mov dx,GC_INDEX + mov al,GRAPHICS_MODE + out dx,al + inc dx + mov al,02h + out dx,al +; +; Enable writes to all 4 planes. +; + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + inc dx + mov al,0fh + out dx,al +; +; Point ES:DI to the display memory byte in which the first pixel +; of the image goes, with AH set up as the bit mask to access that +; pixel within the addressed byte. +; + mov ax,SCREEN_WIDTH_IN_BYTES + mul cx ;offset of start of top scan line + mov di,ax + mov cl,bl + and cl,111b + mov ah,80h ;set AH to the bit mask for the + shr ah,cl ; initial pixel + shr bx,1 + shr bx,1 + shr bx,1 ;X in bytes + add di,bx ;offset of upper-left byte of image + mov bx,DISPLAY_MEMORY_SEGMENT + mov es,bx ;ES:DI points to the byte at which the + ; upper left of the image goes +; +; Get the width and height of the image. +; + mov cx,[si] ;get the width + inc si + inc si + mov bx,[si] ;get the height + inc si + inc si + mov dx,GC_INDEX + mov al,BIT_MASK + out dx,al ;leave the GC Index register pointing + inc dx ; to the Bit Mask register +RowLoop: + + push ax ;preserve the left column's bit mask + push cx ;preserve the width + push di ;preserve the destination offset + +ColumnLoop: + mov al,ah + out dx,al ;set the bit mask to draw this pixel + mov al,es:[di] ;load the latches + mov al,[si] ;get the next two chunky pixels + shr al,1 + shr al,1 + shr al,1 + shr al,1 ;move the first pixel into the lsb + stosb ;draw the first pixel + ror ah,1 ;move mask to next pixel position + jc CheckMorePixels ;is next pixel in the adjacent byte? + dec di ;no + +CheckMorePixels: + dec cx ;see if there are any more pixels + jz AdvanceToNextScanLine ; across in image + mov al,ah + out dx,al ;set the bit mask to draw this pixel + mov al,es:[di] ;load the latches + lodsb ;get the same two chunky pixels again + ; and advance pointer to the next + ; two pixels + stosb ;draw the second of the two pixels + ror ah,1 ;move mask to next pixel position + jc CheckMorePixels2;is next pixel in the adjacent byte? + dec di ;no + +CheckMorePixels2: + loop ColumnLoop ;see if there are any more pixels + ; across in the image + jmp short CheckMoreScanLines + +AdvanceToNextScanLine: + inc si ;advance to the start of the next + ; scan line in the image + +CheckMoreScanLines: + pop di ;get back the destination offset + pop cx ;get back the width + pop ax ;get back the left column's bit mask + add di,SCREEN_WIDTH_IN_BYTES + ;point to the start of the next scan + ; line of the image + dec bx ;see if there are any more scan lines + jnz RowLoop ; in the image + ret +DrawFromChunkyBitmap endp +Code ends + end Start diff --git a/tests/pc/vga/L27-2.ASM b/tests/pc/vga/L27-2.ASM new file mode 100644 index 000000000..31cd9b8c9 --- /dev/null +++ b/tests/pc/vga/L27-2.ASM @@ -0,0 +1,327 @@ +; Program to illustrate one use of write mode 2 of the VGA and EGA by +; drawing lines in color patterns. +; +; Assemble with MASM or TASM +; +; By Michael Abrash +; +Stack segment para stack 'STACK' + db 512 dup(0) +Stack ends + +SCREEN_WIDTH_IN_BYTES equ 80 +GRAPHICS_SEGMENT equ 0a000h ;mode 10 bit-map segment + +SC_INDEX equ 3c4h ;Sequence Controller Index register +MAP_MASK equ 2 ;index of Map Mask register +GC_INDEX equ 03ceh ;Graphics Controller Index reg +GRAPHICS_MODE equ 5 ;index of Graphics Mode reg +BIT_MASK equ 8 ;index of Bit Mask reg + +Data segment para common 'DATA' +Pattern0 db 16 + db 0, 1, 2, 3, 4, 5, 6, 7, 8 + db 9, 10, 11, 12, 13, 14, 15 +Pattern1 db 6 + db 2, 2, 2, 10, 10, 10 +Pattern2 db 8 + db 15, 15, 15, 0, 0, 15, 0, 0 +Pattern3 db 9 + db 1, 1, 1, 2, 2, 2, 4, 4, 4 +Data ends + +Code segment para public 'CODE' + assume cs:Code, ds:Data +Start proc near + mov ax,Data + mov ds,ax + mov ax,10h + int 10h ;select video mode 10h (640x350) +; +; Draw 8 radial lines in upper-left quadrant in pattern 0. +; + mov bx,0 + mov cx,0 + mov si,offset Pattern0 + call QuadrantUp +; +; Draw 8 radial lines in upper-right quadrant in pattern 1. +; + mov bx,320 + mov cx,0 + mov si,offset Pattern1 + call QuadrantUp +; +; Draw 8 radial lines in lower-left quadrant in pattern 2. +; + mov bx,0 + mov cx,175 + mov si,offset Pattern2 + call QuadrantUp +; +; Draw 8 radial lines in lower-right quadrant in pattern 3. +; + mov bx,320 + mov cx,175 + mov si,offset Pattern3 + call QuadrantUp +; +; Wait for a key before returning to text mode and ending. +; + mov ah,01h + int 21h + mov ax,03h + int 10h + mov ah,4ch + int 21h +; +; Draws 8 radial lines with specified pattern in specified mode 10h +; quadrant. +; +; Input: +; BX = X coordinate of upper left corner of quadrant +; CX = Y coordinate of upper left corner of quadrant +; SI = pointer to pattern, in following form: +; Byte 0: Length of pattern +; Byte 1: Start of pattern, one color per byte +; +; AX, BX, CX, DX destroyed +; +QuadrantUp proc near + add bx,160 + add cx,87 ;point to the center of the quadrant + mov ax,0 + mov dx,160 + call LineUp ;draw horizontal line to right edge + mov ax,1 + mov dx,88 + call LineUp ;draw diagonal line to upper right + mov ax,2 + mov dx,88 + call LineUp ;draw vertical line to top edge + mov ax,3 + mov dx,88 + call LineUp ;draw diagonal line to upper left + mov ax,4 + mov dx,161 + call LineUp ;draw horizontal line to left edge + mov ax,5 + mov dx,88 + call LineUp ;draw diagonal line to lower left + mov ax,6 + mov dx,88 + call LineUp ;draw vertical line to bottom edge + mov ax,7 + mov dx,88 + call LineUp ;draw diagonal line to bottom right + ret +QuadrantUp endp +; +; Draws a horizontal, vertical, or diagonal line (one of the eight +; possible radial lines) of the specified length from the specified +; starting point. +; +; Input: +; AX = line direction, as follows: +; 3 2 1 +; 4 * 0 +; 5 6 7 +; BX = X coordinate of starting point +; CX = Y coordinate of starting point +; DX = length of line (number of pixels drawn) +; +; All registers preserved. +; +; Table of vectors to routines for each of the 8 possible lines. +; +LineUpVectors label word + dw LineUp0, LineUp1, LineUp2, LineUp3 + dw LineUp4, LineUp5, LineUp6, LineUp7 + +; +; Macro to draw horizontal, vertical, or diagonal line. +; +; Input: +; XParm = 1 to draw right, -1 to draw left, 0 to not move horz. +; YParm = 1 to draw up, -1 to draw down, 0 to not move vert. +; BX = X start location +; CX = Y start location +; DX = number of pixels to draw +; DS:SI = line pattern +; +MLineUp macro XParm, YParm + local LineUpLoop, CheckMoreLine + mov di,si ;set aside start offset of pattern + lodsb ;get length of pattern + mov ah,al + +LineUpLoop: + lodsb ;get color of this pixel... + call DotUpInColor ;...and draw it +if XParm EQ 1 + inc bx +endif +if XParm EQ -1 + dec bx +endif +if YParm EQ 1 + inc cx +endif +if YParm EQ -1 + dec cx +endif + dec ah ;at end of pattern? + jnz CheckMoreLine + mov si,di ;get back start of pattern + lodsb + mov ah,al ;reset pattern count + +CheckMoreLine: + dec dx + jnz LineUpLoop + jmp LineUpEnd + endm + +LineUp proc near + push ax + push bx + push cx + push dx + push si + push di + push es + + mov di,ax + + mov ax,GRAPHICS_SEGMENT + mov es,ax + + push dx ;save line length +; +; Enable writes to all planes. +; + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + inc dx + mov al,0fh + out dx,al +; +; Select write mode 2. +; + mov dx,GC_INDEX + mov al,GRAPHICS_MODE + out dx,al + inc dx + mov al,02h + out dx,al +; +; Vector to proper routine. +; + pop dx ;get back line length + + shl di,1 + jmp cs:[LineUpVectors+di] +; +; Horizontal line to right. +; +LineUp0: + MLineUp 1, 0 +; +; Diagonal line to upper right. +; +LineUp1: + MLineUp 1, -1 +; +; Vertical line to top. +; +LineUp2: + MLineUp 0, -1 +; +; Diagonal line to upper left. +; +LineUp3: + MLineUp -1, -1 +; +; Horizontal line to left. +; +LineUp4: + MLineUp -1, 0 +; +; Diagonal line to bottom left. +; +LineUp5: + MLineUp -1, 1 +; +; Vertical line to bottom. +; +LineUp6: + MLineUp 0, 1 +; +; Diagonal line to bottom right. +; +LineUp7: + MLineUp 1, 1 + +LineUpEnd: + pop es + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret +LineUp endp +; +; Draws a dot in the specified color at the specified location. +; Assumes that the VGA is in write mode 2 with writes to all planes +; enabled and that ES points to display memory. +; +; Input: +; AL = dot color +; BX = X coordinate of dot +; CX = Y coordinate of dot +; ES = display memory segment +; +; All registers preserved. +; +DotUpInColor proc near + push bx + push cx + push dx + push di +; +; Point ES:DI to the display memory byte in which the pixel goes, with +; the bit mask set up to access that pixel within the addressed byte. +; + push ax ;preserve dot color + mov ax,SCREEN_WIDTH_IN_BYTES + mul cx ;offset of start of top scan line + mov di,ax + mov cl,bl + and cl,111b + mov dx,GC_INDEX + mov al,BIT_MASK + out dx,al + inc dx + mov al,80h + shr al,cl + out dx,al ;set the bit mask for the pixel + shr bx,1 + shr bx,1 + shr bx,1 ;X in bytes + add di,bx ;offset of byte pixel is in + mov al,es:[di] ;load latches + pop ax ;get back dot color + stosb ;write dot in desired color + + pop di + pop dx + pop cx + pop bx + ret +DotUpInColor endp +Start endp +Code ends + end Start diff --git a/tests/pc/vga/L27-3.ASM b/tests/pc/vga/L27-3.ASM new file mode 100644 index 000000000..d0c5f0586 --- /dev/null +++ b/tests/pc/vga/L27-3.ASM @@ -0,0 +1,192 @@ +; Program to illustrate flipping from bit-mapped graphics mode to +; text mode and back without losing any of the graphics bit-map. +; +; Assemble with MASM or TASM +; +; By Michael Abrash +; +Stack segment para stack 'STACK' + db 512 dup(0) +Stack ends + +GRAPHICS_SEGMENT equ 0a000h ;mode 10 bit-map segment +TEXT_SEGMENT equ 0b800h ;mode 3 bit-map segment + +SC_INDEX equ 3c4h ;Sequence Controller Index register +MAP_MASK equ 2 ;index of Map Mask register +GC_INDEX equ 3ceh ;Graphics Controller Index register +READ_MAP equ 4 ;index of Read Map register + +Data segment para common 'DATA' + +GStrikeAnyKeyMsg0 label byte + db 0dh, 0ah, 'Graphics mode', 0dh, 0ah + db 'Strike any key to continue...', 0dh, 0ah, '$' + +GStrikeAnyKeyMsg1 label byte + db 0dh, 0ah, 'Graphics mode again', 0dh, 0ah + db 'Strike any key to continue...', 0dh, 0ah, '$' + +TStrikeAnyKeyMsg label byte + db 0dh, 0ah, 'Text mode', 0dh, 0ah + db 'Strike any key to continue...', 0dh, 0ah, '$' + +Plane2Save db 2000h dup (?) ;save area for plane 2 data + ; where font gets loaded +CharAttSave db 4000 dup (?) ;save area for memory wiped + ; out by character/attribute + ; data in text mode +Data ends + +Code segment para public 'CODE' + assume cs:Code, ds:Data +Start proc near + mov ax,10h + int 10h ;select video mode 10h (640x350) +; +; Fill the graphics bit-map with a colored pattern. +; + cld + mov ax,GRAPHICS_SEGMENT + mov es,ax + mov ah,3 ;initial fill pattern + mov cx,4 ;four planes to fill + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al ;leave the SC Index pointing to the + inc dx ; Map Mask register + +FillBitMap: + mov al,10h + shr al,cl ;generate map mask for this plane + out dx,al ;set map mask for this plane + sub di,di ;start at offset 0 + mov al,ah ;get the fill pattern + push cx ;preserve plane count + mov cx,8000h ;fill 32K words + rep stosw ;do fill for this plane + pop cx ;get back plane count + shl ah,1 + shl ah,1 + loop FillBitMap +; +; Put up "strike any key" message. +; + mov ax,Data + mov ds,ax + mov dx,offset GStrikeAnyKeyMsg0 + mov ah,9 + int 21h +; +; Wait for a key. +; + mov ah,01h + int 21h +; +; Save the 8K of plane 2 that will be used by the font. +; + mov dx,GC_INDEX + mov al,READ_MAP + out dx,al + inc dx + mov al,2 + out dx,al ;set up to read from plane 2 + mov ax,Data + mov es,ax + mov ax,GRAPHICS_SEGMENT + mov ds,ax + sub si,si + mov di,offset Plane2Save + mov cx,2000h/2 ;save 8K (length of default font) + rep movsw +; +; Go to text mode without clearing display memory. +; + mov ax,083h + int 10h +; +; Save the text mode bit-map. +; + mov ax,Data + mov es,ax + mov ax,TEXT_SEGMENT + mov ds,ax + sub si,si + mov di,offset CharAttSave + mov cx,4000/2 ;length of one text screen in words + rep movsw +; +; Fill the text mode screen with dots and put up "strike any key" +; message. +; + mov ax,TEXT_SEGMENT + mov es,ax + sub di,di + mov al,'.' ;fill character + mov ah,7 ;fill attribute + mov cx,4000/2 ;length of one text screen in words + rep stosw + mov ax,Data + mov ds,ax + mov dx,offset TStrikeAnyKeyMsg + mov ah,9 + int 21h +; +; Wait for a key. +; + mov ah,01h + int 21h +; +; Restore the text mode screen to the state it was in on entering +; text mode. +; + mov ax,Data + mov ds,ax + mov ax,TEXT_SEGMENT + mov es,ax + mov si,offset CharAttSave + sub di,di + mov cx,4000/2 ;length of one text screen in words + rep movsw +; +; Return to mode 10h without clearing display memory. +; + mov ax,90h + int 10h +; +; Restore the portion of plane 2 that was wiped out by the font. +; + mov dx,SC_INDEX + mov al,MAP_MASK + out dx,al + inc dx + mov al,4 + out dx,al ;set up to write to plane 2 + mov ax,Data + mov ds,ax + mov ax,GRAPHICS_SEGMENT + mov es,ax + mov si,offset Plane2Save + sub di,di + mov cx,2000h/2 ;restore 8K (length of default font) + rep movsw +; +; Put up "strike any key" message. +; + mov ax,Data + mov ds,ax + mov dx,offset GStrikeAnyKeyMsg1 + mov ah,9 + int 21h +; +; Wait for a key before returning to text mode and ending. +; + mov ah,01h + int 21h + mov ax,03h + int 10h + mov ah,4ch + int 21h +Start endp +Code ends + end Start