; This program will draw a multi-colored diagonal line in VGA mode 13h. ; It then draws a rectangle. ; It also illustrates procedure CALL and RET. ; I've also used BIOS interrupt 15h to insert a real time delay ; of approximately 1/10 sec. before drawing each point. ; Press a key at the start and end. .model small .386 .stack 100h .data Hitime EQU 1h ; delay time constants (approximate 1/10 sec.) Lotime EQU 8000h hdtime equ 10 ; 1/100 seconds, used by delay2 changex db 1 ; globals used by drawline procedure changey db 0 slope db 1 .code start: mov ax,0013h ;1 start vga mode 13h with BIOS interrupt 10h int 10h call KEYD ; wait for key press before continuing mov ax,0a000h ;2 set video RAM location into es mov es,ax mov cx,40 ; initial x coordinate mov dx,5 ; initial y coordinate loop0: mov al,dl ; color in al depend on part of coord in dl and al,0fh ; use only 16 colors call PLOT ; call procedure to plot point at cx,dx coords call DELAY ; delay for real-time effect inc cx ; increment x and y coordinates: inc dx cmp dx,175 ; stop when y coord reaches 175 jne loop0 mov cx,5 ; drawcube mov dx,10 mov bx,20 mov al,2 call drawcube ; drawcube jmp ENDPROG ; execute program termination sequence ; line 37 ; The ENDPROG procedure waits for a keystroke, restores text mode ; 03h and quits: ENDPROG: call KEYD mov ax,0003h ;3 reset to text mode int 10h ;3 mov ax,4c00h int 21h ; key delay procedure - wait for keypress before continuing KEYD: push ax ; save ax register before local use mov ah,1 ;k1 DOS interrupt for keyboard input int 21h ;k1 pop ax ; restore ax ret ; pop saved instruction address and jump ; the PLOT procedure plots a point in VGA mode 13h ; It takes y cord in dx, x cord in cx and color in al as parameters ; It assumes ES=a000h. The dx register needs to be saved ; because it's used in 16-bit multiplication. The main trick is ; to compute the offset of video RAM location to store al. PLOT: push dx ; save registers push ax ; mov ax,320 ; prepare for multiplication (line 63) mul dx ; multiply by horizontal resolution to get y coord add ax,cx ; add x coordinate as offset mov bx,ax ; use bx for indirect addressing pop ax ; get color into al register mov es:[bx],al ; write to video RAM pop dx ; restore dx (ax already popped) ret ; drawcube takes x,y or left top corner in cx,dx, width in bx and color in al drawcube: pusha ; push all but segment registers on stack push ax ; extra push cld mov ax,320 mul dx add ax,cx ; compute ram address of starting coord mov di,ax ; use di for indexing pop ax ; restore color mov dx,bx ; dx used as counter for outer loop (rows) outerl: mov cx,bx ; cx used as counter for inner rep loop (columns) rep stosb ; repeat mov es:[di],al then inc di until cx becomes 0 add di,320 sub di,bx ; vram address now point to next row dec dx cmp dx,0 jg outerl popa ; restore registers before return ret ; drawcube ; The DELAY procedure uses BIOS interrupt 15h, function 86h to ; allow the process to suspend itself for a number of ; microseconds (approx) as determined by cx:dx (the registers are ; used as one 32 bit value). After the time has expired, the ; process will be resumed (assuming the operating system is not doing ; something else of higher priority). The value for cx:dx is ; defined by the constants Hitime and Lotime ; NOTE: this delay procedure does not work on Windows NT/2000. DELAY: push ax ; save registers push cx push dx mov cx,Hitime ; move time to delay into cx:dx mov dx,Lotime mov ah,86h ; call bios to suspend process int 15h pop dx ; restore registers and return pop cx pop ax ret ; This delay2 procedure should work for DOS under Windows NT ; The time interval is determined in hundredths of seconds ; by the constant "hdtime". DELAY2: pusha ; (save all registers) mov bx,hdtime ; set interval mov ah,2dh ;1 reset system time xor cx,cx xor dx,dx int 21h ;1 dl2: mov ah,2ch ; int 21h ; read system time mov al,100 ;2 compute hundredths of seconds mul dh xor dh,dh add ax,dx ;2 cmp ax,bx ; see if interval elapsed jl dl2 ; (jump if less than) popa ; restore all registers ret end