The Art of
ASSEMBLY LANGUAGE PROGRAMMING

Chapter Eleven (Part 7)

Table of Content

Chapter Twelve 

CHAPTER ELEVEN:
PROCEDURES AND FUNCTIONS (Part 8)
11.10 - Sample Program
11.10 Sample Program

The following sample program demonstrates several concepts appearing in this chapter, most notably, passing parameters on the stack. This program (Pgm11_1.asm appearing on the companion CD-ROM) manipulates the PC's memory-mapped text video display screen (at address B800:0 for color displays, B000:0 for monochrome displays). It provides routines that "capture" all the data on the screen to an array, write the contents of an array to the screen, clear the screen, scroll one line up or down, position the cursor at an (X,Y) coordinate, and retrieve the current cursor position.

Note that this code was written to demonstrate the use of parameters and local variables. Therefore, it is rather inefficient. As the comments point out, many of the functions this package provides could be written to run much faster using the 80x86 string instructions. See the laboratory exercises for a different version of some of these functions that is written in such a fashion. Also note that this code makes some calls to the PC's BIOS to set and obtain the cursor position as well as clear the screen. See the chapter on BIOS and DOS for more details on these BIOS calls.

; Pgm11_1.asm
;
; Screen Aids.
;
; This program provides some useful screen manipulation routines
; that let you do things like position the cursor, save and restore
; the contents of the display screen, clear the screen, etc.
;
; This program is not very efficient.  It was written to demonstrate
; parameter passing, use of local variables, and direct conversion of
; loops to assembly language.  There are far better ways of doing
; what this program does (running about 5-10x faster) using the 80x86
; string instructions.



                .xlist
                include         stdlib.a
                includelib      stdlib.lib
                .list

                .386                    ;Comment out these two statements
                option  segment:use16   ; if you are not using an 80386.


; ScrSeg- This is the video screen's segment address.  It should be
;               B000 for mono screens and B800 for color screens.

ScrSeg          =       0B800h






dseg            segment para public 'data'

XPosn           word    ?               ;Cursor X-Coordinate (0..79)
YPosn           word    ?               ;Cursor Y-Coordinate (0..24)

; The following array holds a copy of the initial screen data.

SaveScr         word    25 dup (80 dup (?))

dseg            ends


cseg            segment para public 'code'
                assume  cs:cseg, ds:dseg


; Capture-      Copies the data on the screen to the array passed
;               by reference as a parameter.
;
; procedure Capture(var ScrCopy:array[0..24,0..79] of word);
; var x,y:integer;
; begin
;
;       for y := 0 to 24 do
;           for x := 0 to 79 do
;               SCREEN[y,x] := ScrCopy[y,x];
; end;
;
;
; Activation record for Capture:
;
;       |                       |
;       | Previous stk contents |
;       -------------------------
;       |  ScrCopy Seg Adrs     |
;       --                     --
;       | ScrCopy offset Adrs   |
;       -------------------------
;       | Return Adrs (near)    |
;       -------------------------
;       |      Old BP           |
;       ------------------------- <- BP
;       |  X coordinate value   |
;       -------------------------
;       |  Y coordinate value   |
;       -------------------------
;       | Registers, etc.       |
;       ------------------------- <- SP



ScrCopy_cap     textequ <dword ptr [bp+4]>
X_cap           textequ <word ptr [bp-2]>
Y_cap           textequ <word ptr [bp-4]>

Capture         proc
                push    bp
                mov     bp, sp
                sub     sp, 4                   ;Allocate room for locals.

                push    es
                push    ds
                push    ax
                push    bx
                push    di

                mov     bx, ScrSeg              ;Set up pointer to SCREEN
                mov     es, bx                  ; memory (ScrSeg:0).

                lds     di, ScrCopy_cap         ;Get ptr to capture array.

                mov     Y_cap, 0
YLoop:          mov     X_cap, 0
XLoop:          mov     bx, Y_cap
                imul    bx, 80                  ;Screen memory is a 25x80 array
                add     bx, X_cap               ; stored in row major order
                add     bx, bx                  ; with two bytes per element.

                mov     ax, es:[bx]             ;Read character code from screen.
                mov     ds:[di][bx], ax         ;Store away into capture array.

                inc     X_Cap                   ;Repeat for each character on this
                cmp     X_Cap, 80               ; row of characters (each character
                jb      XLoop                   ; in the row is two bytes).

                inc     Y_Cap                   ;Repeat for each row on the screen.
                cmp     Y_Cap, 25
                jb      YLoop

                pop     di
                pop     bx
                pop     ax
                pop     ds
                pop     es
                mov     sp, bp
                pop     bp
                ret     4
Capture         endp





; Fill-         Copies array passed by reference onto the screen.
;
; procedure Fill(var ScrCopy:array[0..24,0..79] of word);
; var x,y:integer;
; begin
;
;       for y := 0 to 24 do
;           for x := 0 to 79 do
;               ScrCopy[y,x] := SCREEN[y,x];
; end;
;
;
; Activation record for Fill:
;
;       |                       |
;       | Previous stk contents |
;       -------------------------
;       |  ScrCopy Seg Adrs     |
;       --                     --
;       | ScrCopy offset Adrs   |
;       -------------------------
;       | Return Adrs (near)    |
;       -------------------------
;       |      Old BP           |
;       ------------------------- <- BP
;       |  X coordinate value   |
;       -------------------------
;       |  Y coordinate value   |
;       -------------------------
;       | Registers, etc.       |
;       ------------------------- <- SP



ScrCopy_fill    textequ <dword ptr [bp+4]>
X_fill          textequ <word ptr [bp-2]>
Y_fill          textequ <word ptr [bp-4]>

Fill            proc
                push    bp
                mov     bp, sp
                sub     sp, 4

                push    es
                push    ds
                push    ax
                push    bx
                push    di

                mov     bx, ScrSeg              ;Set up pointer to SCREEN
                mov     es, bx                  ; memory (ScrSeg:0).

                lds     di, ScrCopy_fill        ;Get ptr to data array.

                mov     Y_Fill, 0
YLoop:          mov     X_Fill, 0
XLoop:          mov     bx, Y_Fill
                imul    bx, 80                  ;Screen memory is a 25x80 array
                add     bx, X_Fill              ; stored in row major order
                add     bx, bx                  ; with two bytes per element.

                mov     ax, ds:[di][bx]         ;Store away into capture array.
                mov     es:[bx], ax             ;Read character code from screen.

                inc     X_Fill                  ;Repeat for each character on this
                cmp     X_Fill, 80              ; row of characters (each character
                jb      XLoop                   ; in the row is two bytes).

                inc     Y_Fill                  ;Repeat for each row on the screen.
                cmp     Y_Fill, 25
                jb      YLoop

                pop     di
                pop     bx
                pop     ax
                pop     ds
                pop     es
                mov     sp, bp
                pop     bp
                ret     4
Fill            endp





; Scroll_up-    Scrolls the screen up on line.  It does this by copying the second line
;               to the first, the third line to the second, the fourth line to the third,
;               etc.
;
; procedure Scroll_up;
; var x,y:integer;
; begin
;       for y := 1 to 24 do
;           for x := 0 to 79 do
;               SCREEN[Y-1,X] := SCREEN[Y,X];
; end;
;
; Activation record for Scroll_up:
;
;       |                       |
;       | Previous stk contents |
;       -------------------------
;       | Return Adrs (near)    |
;       -------------------------
;       |      Old BP           |
;       ------------------------- <- BP
;       |  X coordinate value   |
;       -------------------------
;       |  Y coordinate value   |
;       -------------------------
;       | Registers, etc.       |
;       ------------------------- <- SP



X_su            textequ <word ptr [bp-2]>
Y_su            textequ <word ptr [bp-4]>

Scroll_up       proc
                push    bp
                mov     bp, sp
                sub     sp, 4                   ;Make room for X, Y.

                push    ds
                push    ax
                push    bx

                mov     ax, ScrSeg
                mov     ds, ax
                mov     Y_su, 0
su_Loop1:       mov     X_su, 0

su_Loop2:       mov     bx, Y_su                ;Compute index into screen
                imul    bx, 80                  ; array.
                add     bx, X_su
                add     bx, bx                  ;Remember, this is a word array.
        
                mov     ax, ds:[bx+160]         ;Fetch word from source line.
                mov     ds:[bx], ax             ;Store into dest line.

                inc     X_su
                cmp     X_su, 80
                jb      su_Loop2

                inc     Y_su
                cmp     Y_su, 80
                jb      su_Loop1

                pop     bx
                pop     ax
                pop     ds
                mov     sp, bp
                pop     bp
                ret
Scroll_up       endp






; Scroll_dn-    Scrolls the screen down one line.  It does this by copying the 24th line
;               to the 25th, the 23rd line to the 24th, the 22nd line to the 23rd,
;               etc.
;
; procedure Scroll_dn;
; var x,y:integer;
; begin
;       for y := 23 downto 0 do
;           for x := 0 to 79 do
;               SCREEN[Y+1,X] := SCREEN[Y,X];
; end;
;
; Activation record for Scroll_dn:
;
;       |                       |
;       | Previous stk contents |
;       -------------------------
;       | Return Adrs (near)    |
;       -------------------------
;       |      Old BP           |
;       ------------------------- <- BP
;       |  X coordinate value   |
;       -------------------------
;       |  Y coordinate value   |
;       -------------------------
;       | Registers, etc.       |
;       ------------------------- <- SP


X_sd            textequ <word ptr [bp-2]>
Y_sd            textequ <word ptr [bp-4]>

Scroll_dn       proc
                push    bp
                mov     bp, sp
                sub     sp, 4                   ;Make room for X, Y.

                push    ds
                push    ax
                push    bx

                mov     ax, ScrSeg
                mov     ds, ax
                mov     Y_sd, 23
sd_Loop1:       mov     X_sd, 0

sd_Loop2:       mov     bx, Y_sd                ;Compute index into screen
                imul    bx, 80                  ; array.
                add     bx, X_sd
                add     bx, bx                  ;Remember, this is a word array.
        
                mov     ax, ds:[bx]             ;Fetch word from source line.
                mov     ds:[bx+160], ax         ;Store into dest line.

                inc     X_sd
                cmp     X_sd, 80
                jb      sd_Loop2

                dec     Y_sd
                cmp     Y_sd, 0
                jge     sd_Loop1

                pop     bx
                pop     ax
                pop     ds
                mov     sp, bp
                pop     bp
                ret
Scroll_dn       endp




; GotoXY-       Positions the cursor at the specified X, Y coordinate.
;
; procedure gotoxy(x,y:integer);
; begin
;       BIOS(posnCursor,x,y);
; end;
;
; Activation record for GotoXY
;
;       |                       |
;       | Previous stk contents |
;       -------------------------
;       |  X coordinate value   |
;       -------------------------
;       |  Y coordinate value   |
;       -------------------------
;       | Return Adrs (near)    |
;       -------------------------
;       |      Old BP           |
;       ------------------------- <- BP
;       | Registers, etc.       |
;       ------------------------- <- SP


X_gxy           textequ <byte ptr [bp+6]>
Y_gxy           textequ <byte ptr [bp+4]>

GotoXY          proc
                push    bp
                mov     bp, sp
                push    ax
                push    bx
                push    dx

                mov     ah, 2                   ;Magic BIOS value for gotoxy.
                mov     bh, 0                   ;Display page zero.
                mov     dh, Y_gxy               ;Set up BIOS (X,Y) parameters.
                mov     dl, X_gxy
                int     10h                     ;Make the BIOS call.

                pop     dx
                pop     bx
                pop     ax
                mov     sp, bp
                pop     bp
                ret     4
GotoXY          endp



; GetX-         Returns cursor X-Coordinate in the AX register.

GetX            proc
                push    bx
                push    cx
                push    dx

                mov     ah, 3           ;Read X, Y coordinates from
                mov     bh, 0           ; BIOS
                int     10h

                mov     al, dl          ;Return X coordinate in AX.
                mov     ah, 0

                pop     dx
                pop     cx
                pop     bx
                ret
GetX            endp



; GetY-         Returns cursor Y-Coordinate in the AX register.

GetY            proc
                push    bx
                push    cx
                push    dx

                mov     ah, 3
                mov     bh, 0
                int     10h

                mov     al, dh          ;Return Y Coordinate in AX.
                mov     ah, 0

                pop     dx
                pop     cx
                pop     bx
                ret
GetY            endp



; ClearScrn-    Clears the screen and positions the cursor at (0,0).
;
; procedure ClearScrn;
; begin
;       BIOS(Initialize)
; end;

ClearScrn       proc
                push    ax
                push    bx
                push    cx
                push    dx

                mov     ah, 6           ;Magic BIOS number.
                mov     al, 0           ;Clear entire screen.
                mov     bh, 07          ;Clear with black spaces.
                mov     cx, 0000        ;Upper left corner is (0,0)
                mov     dl, 79          ;Lower X-coordinate
                mov     dh, 24          ;Lower Y-coordinate
                int     10h             ;Make the BIOS call.

                push    0               ;Position the cursor to (0,0)
                push    0               ; after the call.
                call    GotoXY

                pop     dx
                pop     cx
                pop     bx
                pop     ax
                ret
ClearScrn       endp




; A short main program to test out the above:

Main            proc
                mov     ax, dseg
                mov     ds, ax
                mov     es, ax
                meminit

; Save the screen as it looks when this program is run.

                push    seg SaveScr
                push    offset SaveScr
                call    Capture

                call    GetX
                mov     XPosn, ax

                call    GetY
                mov     YPosn, ax


; Clear the screen to prepare for our stuff.

                call    ClearScrn

; Position the cursor in the middle of the screen and print some stuff.

                push    30              ;X value
                push    10              ;Y value
                call    GotoXY

                print
                byte    "Screen Manipulatation Demo",0

                push    30
                push    11
                call    GotoXY

                print
                byte    "Press any key to continue",0

                getc


; Scroll the screen up two lines

                call    Scroll_up
                call    Scroll_up
                getc

;Scroll the screen down four lines:

                call    Scroll_dn
                call    Scroll_dn
                call    Scroll_dn
                call    Scroll_dn
                getc




; Restore the screen to what it looked like prior to this call.

                push    seg SaveScr
                push    offset SaveScr
                call    Fill

                push    XPosn
                push    YPosn
                call    GotoXY



Quit:           ExitPgm                 ;DOS macro to quit program.
Main            endp

cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
                end     Main

Chapter Eleven (Part 7)

Table of Content

Chapter Twelve 

Chapter Eleven: Procedures and Functions (Part 8)
27 SEP 1996