assembly: procedures jbwyatt.com

.. 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