; Pgm9_1.ASM ; ; Several examples demonstrating how to convert various ; arithmetic expressions into assembly language. .xlist include stdlib.a includelib stdlib.lib .list dseg segment para public 'data' ; Arbitrary variables this program uses. u word ? v word ? w word ? x word ? y word ? dseg ends cseg segment para public 'code' assume cs:cseg, ds:dseg ; GETI- Reads an integer variable from the user and returns its ; its value in the AX register. geti textequ <call _geti> _geti proc push es push di getsm atoi free pop di pop es ret _geti endp Main proc mov ax, dseg mov ds, ax mov es, ax meminit print byte "Abitrary expression program",cr,lf byte "---------------------------",cr,lf byte lf byte "Enter a value for u: ",0 geti mov u, ax print byte "Enter a value for v: ",0 geti mov v, ax print byte "Enter a value for w: ",0 geti mov w, ax print byte "Enter a non-zero value for x: ",0 geti mov x, ax print byte "Enter a non-zero value for y: ",0 geti mov y, ax ; Okay, compute Z := (X+Y)*(U+V*W)/X and print the result. print byte cr,lf byte "(X+Y) * (U+V*W)/X is ",0 mov ax, v ;Compute V*W imul w ; and then add in add ax, u ; U. mov bx, ax ;Save in a temp location for now. mov ax, x ;Compute X+Y, multiply this add ax, y ; sum by the result above, imul bx ; and then divide the whole idiv x ; thing by X. puti putcr ; Compute ((X-Y*U) + (U*V) - W)/(X*Y) print byte "((X-Y*U) + (U*V) - W)/(X*Y) = ",0 mov ax, y ;Compute y*u first imul u mov dx, X ;Now compute X-Y*U sub dx, ax mov cx, dx ;Save in temp mov ax, u ;Compute U*V imul V add cx, ax ;Compute (X-Y*U) + (U*V) sub cx, w ;Compute ((X-Y*U) + (U*V) - W) mov ax, x ;Compute (X*Y) imul y xchg ax, cx cwd ;Compute NUMERATOR/(X*Y) idiv cx puti putcr 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
; Pgm9_2.ASM ; ; This program demonstrates DeMorgan's theorems and ; various other logical computations. .xlist include stdlib.a includelib stdlib.lib .list dseg segment para public 'data' ; Boolean input variables for the various functions ; we are going to test. a byte 0 b byte 0 dseg ends cseg segment para public 'code' assume cs:cseg, ds:dseg ; Get0or1- Reads a "0" or "1" from the user and returns its ; its value in the AX register. get0or1 textequ <call _get0or1> _get0or1 proc push es push di getsm atoi free pop di pop es ret _get0or1 endp Main proc mov ax, dseg mov ds, ax mov es, ax meminit print byte "Demorgan's Theorems",cr,lf byte "-------------------",cr,lf byte lf byte "According to Demorgan's theorems, all results " byte "between the dashed lines",cr,lf byte "should be equal.",cr,lf byte lf byte "Enter a value for a: ",0 get0or1 mov a, al print byte "Enter a value for b: ",0 get0or1 mov b, al print byte "---------------------------------",cr,lf byte "Computing not (A and B): ",0 mov ah, 0 mov al, a and al, b xor al, 1 ;Logical NOT operation. puti putcr print byte "Computing (not A) OR (not B): ",0 mov al, a xor al, 1 mov bl, b xor bl, 1 or al, bl puti print byte cr,lf byte "---------------------------------",cr,lf byte "Computing (not A) OR B: ",0 mov al, a xor al, 1 or al, b puti print byte cr,lf byte "Computing not (A AND (not B)): ",0 mov al, b xor al, 1 and al, a xor al, 1 puti print byte cr,lf byte "---------------------------------",cr,lf byte "Computing (not A) OR B: ",0 mov al, a xor al, 1 or al, b puti print byte cr,lf byte "Computing not (A AND (not B)): ",0 mov al, b xor al, 1 and al, a xor al, 1 puti print byte cr,lf byte "---------------------------------",cr,lf byte "Computing not (A OR B): ",0 mov al, a or al, b xor al, 1 puti print byte cr,lf byte "Computing (not A) AND (not B): ",0 mov al, a xor al, 1 and bl, b xor bl, 1 and al, bl puti print byte cr,lf byte "---------------------------------",cr,lf byte 0 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
; Pgm9_3.ASM ; ; This sample program provides two procedures that read and write ; 64-bit unsigned integer values on an 80386 or later processor. .xlist include stdlib.a includelib stdlib.lib .list .386 option segment:use16 dp textequ <dword ptr> byp textequ <byte ptr> dseg segment para public 'data' ; Acc64 is a 64 bit value that the ATOU64 routine uses to input ; a 64-bit value. Acc64 qword 0 ; Quotient holds the result of dividing the current PUTU value by ; ten. Quotient qword 0 ; NumOut holds the string of digits created by the PUTU64 routine. NumOut byte 32 dup (0) ; A sample test string for the ATOI64 routine: LongNumber byte "123456789012345678",0 dseg ends cseg segment para public 'code' assume cs:cseg, ds:dseg ; ATOU64- On entry, ES:DI point at a string containing a ; sequence of digits. This routine converts that ; string to a 64-bit integer and returns that ; unsigned integer value in EDX:EAX. ; ; This routine uses the algorithm: ; ; Acc := 0 ; while digits left ; ; Acc := (Acc * 10) + (Current Digit - '0') ; Move on to next digit ; ; endwhile ATOU64 proc near push di ;Save because we modify it. mov dp Acc64, 0 ;Initialize our accumulator. mov dp Acc64+4, 0 ; While we've got some decimal digits, process the input string: sub eax, eax ;Zero out eax's H.O. 3 bytes. WhileDigits: mov al, es:[di] xor al, '0' ;Translates '0'..'9' -> 0..9 cmp al, 10 ; and everything else is > 9. ja NotADigit ; Multiply Acc64 by ten. Use shifts and adds to accomplish this: shl dp Acc64, 1 ;Compute Acc64*2 rcl dp Acc64+4, 1 push dp Acc64+4 ;Save Acc64*2 push dp Acc64 shl dp Acc64, 1 ;Compute Acc64*4 rcl dp Acc64+4, 1 shl dp Acc64, 1 ;Compute Acc64*8 rcl dp Acc64+4, 1 pop edx ;Compute Acc64*10 as add dp Acc64, edx ; Acc64*2 + Acc64*8 pop edx adc dp Acc64+4, edx ; Add in the numeric equivalent of the current digit. ; Remember, the H.O. three words of eax contain zero. add dp Acc64, eax ;Add in this digit inc di ;Move on to next char. jmp WhileDigits ;Repeat for all digits. ; Okay, return the 64-bit integer value in eax. NotADigit: mov eax, dp Acc64 mov edx, dp Acc64+4 pop di ret ATOU64 endp ; PUTU64- On entry, EDX:EAX contain a 64-bit unsigned value. ; Output a string of decimal digits providing the ; decimal representation of that value. ; ; This code uses the following algorithm: ; ; di := 30; ; while edx:eax <> 0 do ; ; OutputNumber[di] := digit; ; edx:eax := edx:eax div 10 ; di := di - 1; ; ; endwhile ; Output digits from OutNumber[di+1] ; through OutputNumber[30] PUTU64 proc push es push eax push ecx push edx push di pushf mov di, dseg ;This is where the output mov es, di ; string will go. lea di, NumOut+30 ;Store characters in string std ; backwards. mov byp es:[di+1],0 ;Output zero terminating byte. ; Save the value to print so we can divide it by ten using an ; extended precision division operation. mov dp Quotient, eax mov dp Quotient+4, edx ; Okay, begin converting the number into a string of digits. mov ecx, 10 ;Value to divide by. DivideLoop: mov eax, dp Quotient+4 ;Do a 64-bit by sub edx, edx ; 32-bit division div ecx ; (see the text mov dp Quotient+4, eax ; for details). mov eax, dp Quotient div ecx mov dp Quotient, eax ; At this time edx (dl, actually) contains the remainder of the ; above division by ten, so dl is in the range 0..9. Convert ; this to an ASCII character and save it away. mov al, dl or al, '0' stosb ; Now check to see if the result is zero. When it is, we can ; quit. mov eax, dp Quotient or eax, dp Quotient+4 jnz DivideLoop OutputNumber: inc di puts popf pop di pop edx pop ecx pop eax pop es ret PUTU64 endp ; The main program provides a simple test of the two routines ; above. Main proc mov ax, dseg mov ds, ax mov es, ax meminit lesi LongNumber call ATOU64 call PutU64 printf byte cr,lf byte "%x %x %x %x",cr,lf,0 dword Acc64+6, Acc64+4, Acc64+2, Acc64 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
; Pgm9_4.ASM ; ; This program demonstrates how to pack and unpack ; data types. It reads in a month, day, and year value. ; It then packs these values into the format the textbook ; presents in chapter two. Finally, it unpacks this data ; and calls the stdlib DTOA routine to print it as text. .xlist include stdlib.a includelib stdlib.lib .list dseg segment para public 'data' Month byte ? ;Holds month value (1-12) Day byte ? ;Holds day value (1-31) Year byte ? ;Holds year value (80-99) Date word ? ;Packed data goes in here. dseg ends cseg segment para public 'code' assume cs:cseg, ds:dseg ; GETI- Reads an integer variable from the user and returns its ; its value in the AX register. geti textequ <call _geti> _geti proc push es push di getsm atoi free pop di pop es ret _geti endp Main proc mov ax, dseg mov ds, ax mov es, ax meminit print byte "Date Conversion Program",cr,lf byte "-----------------------",cr,lf byte lf,0 ; Get the month value from the user. ; Do a simple check to make sure this value is in the range ; 1-12. Make the user reenter the month if it is not. GetMonth: print byte "Enter the month (1-12): ",0 geti mov Month, al cmp ax, 0 je BadMonth cmp ax, 12 jbe GoodMonth BadMonth: print byte "Illegal month value, please re-enter",cr,lf,0 jmp GetMonth GoodMonth: ; Okay, read the day from the user. Again, do a simple ; check to see if the date is valid. Note that this code ; only checks to see if the day value is in the range 1-31. ; It does not check those months that have 28, 29, or 30 ; day months. GetDay: print byte "Enter the day (1-31): ",0 geti mov Day, al cmp ax, 0 je BadDay cmp ax, 31 jbe GoodDay BadDay: print byte "Illegal day value, please re-enter",cr,lf,0 jmp GetDay GoodDay: ; Okay, get the year from the user. ; This check is slightly more sophisticated. If the user ; enters a year in the range 1980-1999, it will automatically ; convert it to 80-99. All other dates outside the range ; 80-99 are illegal. GetYear: print byte "Enter the year (80-99): ",0 geti cmp ax, 1980 jb TestYear cmp ax, 1999 ja BadYear sub dx, dx ;Zero extend year to 32 bits. mov bx, 100 div bx ;Compute year mod 100. mov ax, dx jmp GoodYear TestYear: cmp ax, 80 jb BadYear cmp ax, 99 jbe GoodYear BadYear: print byte "Illegal year value. Please re-enter",cr,lf,0 jmp GetYear GoodYear: mov Year, al ; Okay, take these input values and pack them into the following ; 16-bit format: ; ; bit 15 8 7 0 ; | | | | ; MMMMDDDD DYYYYYYY mov ah, 0 mov bh, ah mov al, Month ;Put Month into bit positions mov cl, 4 ; 12..15 ror ax, cl mov bl, Day ;Put Day into bit positions mov cl, 7 ; 7..11. shl bx, cl or ax, bx ;Create MMMMDDDD D0000000 or al, Year ;Create MMMMDDDD DYYYYYYY mov Date, ax ;Save away packed date. ; Print out the packed date (in hex): print byte "Packed date = ",0 putw putcr ; Okay, the following code demonstrates how to unpack this date ; and put it in a form the standard library's LDTOAM routine can ; use. mov ax, Date ;First, extract Month mov cl, 4 shr ah, cl mov dh, ah ;LDTOAM needs month in DH. mov ax, Date ;Next get the day. shl ax, 1 and ah, 11111b mov dl, ah ;Day needs to be in DL. mov cx, Date ;Now process the year. and cx, 7fh ;Strip all but year bits. print byte "Date: ",0 LDTOAM ;Convert to a string puts free putcr 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