.. PROC intro
Problems can be divided into smaller tasks to make them more manageable
A PROC is the ASM equivalent of a C++ function or C# method
sample PROC
.
.
ret
sample ENDP
CALL instruction calls a procedure
pushes address of next instruction onto the stack
copies address of called procedure into EIP
RET instruction returns from a procedure
pops top of stack into EIP
;---------------------------------------------------------
SumOf PROC
;
; Calculates and returns the sum of three 32-bit integers.
; Receives: AX, BX, CX, the three integers. May be signed or unsigned.
; Returns: AX = sum, and the status flags (Carry, Overflow, etc.) are changed.
;---------------------------------------------------------
add ax, bx
add ax, cx
ret
SumOf ENDP
0025 is the offset of the instruction following the CALL instruction
0040 is the offset of the first instruction inside MySub
main PROC
0020 call SumOf ; 40 to ip, 25 to stack
0025 mov ax, bx
.
.
main ENDP
SumOf PROC
0040 mov ax, dx
.
.
ret ; pop stack, 25 to eip
SumOf ENDP
Procedures can call other procedures and so on...
return addresses are pushed onto the stack as calls are made
... and popped off as each returns
.. Using a Proc
; You may customize this and other start-up templates;
; The location of this template is c:\emu8086\inc\0_com_template.txt
include emu8086.inc
org 100h
mov ax, 8
mov bx, 3
mov cx, 99
call SumOf
call PRINT_NUM
ret
SumOf PROC
;
; Calculates and returns the sum of three 32-bit integers.
; Receives: AX, BX, CX, the three integers. May be signed or unsigned.
; Returns: AX = sum, and the status flags (Carry, Overflow, etc.) are changed.
;---------------------------------------------------------
add ax, bx
add ax, cx
ret
SumOf ENDP
; PROCEDURES (call)
DEFINE_PRINT_NUM ; prints AX signed
DEFINE_PRINT_NUM_UNS ; prints AX unsigned - required for print_num.
END
.. Making a PROC general
Parameters: make procedures flexible
==========
Registers are an accepted way to pass parameters in assembly, but one
must be VERY careful. The stack can also be used.
A good procedure might be usable in many different programs
but NOT if it refers to specific variable names declared elsewhere...
This version of ArraySum returns the sum of ANY word array
Address of array passed in SI.
The array count is passed in CX
The sum is returned in AX:
ArraySum PROC
; Receives: SI points to an array of doublewords,
; CX = number of array elements.
; Returns: AX = sum
;-----------------------------------------------------
mov ax, 0 ; set the sum to zero
L1: add ax, [si] ; add each integer to sum
add si, 2 ; point to next integer
loop L1 ; repeat for array size
ret
ArraySum ENDP
.. 16 bit ASM: temperature convert
; centigrade (celsius) to fahrenheit calculation and vice-versa.
; it may not be accurate, because of integer division.
; this program prints out the result in binary code.
; to see result in hexadecimal or decimal form click vars.
include emu8086.inc
name "celsi"
org 100h
jmp START
; DATA
tc db 0 ; t celsius.
tf db 32 ; t fahrenheit.
result1 db ? ; result in fahrenheit.
result2 db ? ; result in celsius.
START:
; convert celsius to fahrenheit according
; to this formula: f = c * 9 / 5 + 32
mov cl, tc
mov al, 9
imul cl
mov cl, 5
idiv cl
add al, 32
mov result1, al
mov bl, result1
call bprint ; print bl
PRINTN
xor ax,ax
mov al, bl
call Print_NUM_UNS ; print bl
PRINTN
; convert fahrenheit to celsius according
; to this formula: c = (f - 32) * 5 / 9
mov cl, tf
sub cl, 32
mov al, 5
imul cl
mov cl, 9
idiv cl
mov result2, al
; call the PRINT PROCEDURE
mov bl, result2
call bPrint ; print bl
PRINTN
xor ax,ax
mov al, bl
call Print_NUM_UNS ; print bl
PRINTN
; wait for any key press...
mov ah, 0
int 16h
ret ; return to the operating system.
;=========================================
; procedure prints the binary value of bl
bPrint PROC
; save all
pusha
; print result in binary:
mov cx, 8
p1: mov ah, 2
mov dl, '0'
test bl, 10000000b ;test first bit.
jz zero
mov dl, '1'
zero: int 21h ;print function.
shl bl, 1
loop p1
; print binary suffix:
mov dl, 'b'
int 21h
; print carrige return and new line:
mov dl, 0Dh
int 21h
mov dl, 0Ah
int 21h
;restore all
popa
ret ; return to the caller
bPrint ENDP
; PROCEDURES (call)
DEFINE_PRINT_NUM ; prints AX signed
DEFINE_PRINT_NUM_UNS ; prints AX unsigned - required for print_num.
end
;==========================================
.. Create a PROC
Build a procedure called "DoIt" that will take whatever is in the AL register,
ADD 10, and PRINT it.
TELL if there is unsigned overflow!!!
INCLUDE emu8086.inc
org 100h
xor ax, ax
mov al, 100
PRINTN "Calling with 100"
call DoIt
xor ax, ax
mov al, 0
PRINTN "Calling with 0"
call DoIt
xor ax, ax
mov al, 250
PRINTN "Calling with 250"
call DoIt
ret
DoIt proc
add al, 10
PRINT "The number + 10 is "
call PRINT_NUM
PRINTN
; if the carry flag is set
jc BIG
jmp R
BIG:
PRINTN "Overflow! Bad Result"
R:
ret
DoIt ENDP
DEFINE_PRINT_NUM ; prints AX signed
DEFINE_PRINT_NUM_UNS ; prints AX unsigned
END
.. Example code: summing elements - recursion
; This program demonstrates recursion as it sums the integers 1-n
INCLUDE emu8086.inc
org 100h
mov cx, 20 ; count = 20 (n)
mov ax, 0 ; holds the sum
call CalcSum ; calculate sum
L1: call PRINT_NUM ; display ax
PRINTN
ret
;--------------------------------------------------------
CalcSum PROC
; Calculates the sum of a list of integers
; Receives: CX = count
; Returns: AX = sum
;--------------------------------------------------------
cmp cx,0 ; check counter value
jz L2 ; quit if zero
add ax, cx ; otherwise, add to sum
dec cx ; decrement counter
call CalcSum ; recursive call CAREFUL!!!
L2: ret
CalcSum ENDP
DEFINE_PRINT_NUM ; prints AX signed
DEFINE_PRINT_NUM_UNS ; prints AX unsigned
END