Skip to content

Control Flow and Subroutines ​

Complete Lab Manual

For the complete experiment including learning objectives, theoretical background, and detailed explanations, download the PDF manual: Download Experiment 3 PDF

Examples ​

Example 1: Find Maximum Element in Array ​

This example demonstrates how to find the maximum element in an array using a standard for loop structure.

asm
        AREA    RESET, CODE, READONLY
        EXPORT  __Vectors
__Vectors
        DCD     0x20001000          ; Initial SP
        DCD     Reset_Handler       ; Reset vector
        ALIGN

        AREA    MYCODE, CODE, READONLY
        ENTRY
        EXPORT  Reset_Handler

; Find maximum element in ARR[0..LEN-1]
; Result (max) is written to MAXRES.
Reset_Handler
        LDR     R0, =ARR            ; R0 = &ARR[0]
        MOV     R1, #0              ; R1 = i (index)
        LDR     R2, [R0]            ; R2 = max = ARR[0]
for_start
        CMP     R1, #LEN            ; i >= LEN ?
        BGE     for_end             ; yes -> done

        LDR     R3, [R0, R1, LSL #2]; R3 = ARR[i]
        CMP     R3, R2              ; if ARR[i] > max
        MOVGT   R2, R3              ;    max = ARR[i]
        ADD     R1, R1, #1          ; i++
        B       for_start
for_end
        LDR     R4, =MAXRES         ; store result for easy checking
        STR     R2, [R4]
STOP    B       STOP

        AREA    CONSTANTS, DATA, READONLY
ARR     DCD     10, 20, 30, -5, 11, 0
LEN     EQU     6

        AREA    MYDATA, DATA, READWRITE
MAXRES  DCD     0                   ; expect 30

        END

Check: Verify that the maximum element is correctly identified and stored in MAXRES.

Example 2: Count Uppercase Letters in String ​

This example demonstrates how to process a null-terminated string and count the number of uppercase letters (A-Z) using a while-loop structure.

asm
        AREA    RESET, CODE, READONLY
        EXPORT  __Vectors
__Vectors
        DCD     0x20001000          ; Initial SP
        DCD     Reset_Handler       ; Reset vector
        ALIGN

        AREA    MYCODE, CODE, READONLY
        ENTRY
        EXPORT  Reset_Handler

; Count uppercase ASCII letters in the null-terminated string MYSTR.
; Result (count) is written to UPPERCOUNT.
Reset_Handler
        LDR     R0, =MYSTR          ; R0 = ptr to string
        MOV     R1, #0              ; R1 = count

while_next
        LDRB    R2, [R0], #1        ; R2 = *p++; post-increment pointer
        CBZ     R2, while_end       ; if '\0' -> exit

        CMP     R2, #'A'            ; below 'A'?
        BLT     while_next
        CMP     R2, #'Z'            ; above 'Z'?
        BGT     while_next

        ADD     R1, R1, #1          ; count++

        B       while_next

while_end
        LDR     R3, =UPPERCOUNT
        STR     R1, [R3]

STOP    B       STOP

        AREA    CONSTANTS, DATA, READONLY
MYSTR   DCB     "Hello ARM World!", 0

        AREA    MYDATA, DATA, READWRITE
UPPERCOUNT DCD  0                   ; expect 5 ('H','A','R','M','W')

        END

Check: Verify that the program correctly counts the uppercase letters and stores the result in UPPERCOUNT.

Example 3: Nested Uppercase Counter with Stack ​

This example demonstrates a nested call: CountUpperNested(ptr) scans a null-terminated string and calls IsUpper(ch) for each character. It shows saving/restoring LR and using a callee-saved register (R4) for the running count.

asm
        AREA    RESET, CODE, READONLY
        EXPORT  __Vectors
__Vectors
        DCD     0x20001000          ; Initial SP
        DCD     Reset_Handler       ; Reset vector
        ALIGN
        AREA    MYCODE, CODE, READONLY
        ENTRY
        EXPORT  Reset_Handler
IsUpper                              ; IsUpper(R0 = ch) -> R0 = 1 if 'A'..'Z', else 0
        CMP     R0, #'A'
        BLT     not_upper
        CMP     R0, #'Z'
        BGT     not_upper
        MOV     R0, #1
        BX      LR
not_upper
        MOV     R0, #0
        BX      LR
CountUpperNested                    ; CountUpperNested(R0 = ptr) -> R0 = Upper Count
        PUSH    {R4, LR}            ; save callee-saved + return address
        MOV     R1, R0              ; R1 = ptr (keep pointer here)
        MOV     R4, #0              ; R4 = count
cu_next
        LDRB    R0, [R1], #1        ; R0 = *ptr++; post-increment pointer in R1
        CBZ     R0, cu_done         ; if null terminator, finish
        BL      IsUpper             ; R0 = 0/1 based on 'A'..'Z'
        ADD     R4, R4, R0          ; count += result
        B       cu_next
cu_done
        MOV     R0, R4              ; return count in R0
        POP     {R4, PC}
Reset_Handler
        LDR     R0, =mystring
        BL      CountUpperNested
        LDR     R2, =UPPERCOUNT
        STR     R0, [R2]
STOP    B       STOP
        AREA    CONSTANTS, DATA, READONLY
mystring DCB    "Hello ARM World!", 0  ; Uppercase: H, A, R, M, W -> 5
        AREA    MYDATA, DATA, READWRITE
UPPERCOUNT  DCD 0                      ; should be 5
        END

Check: Verify that UPPERCOUNT contains 5 for the test string.

Tasks ​

Task 1: Count Vowels in a String ​

Implement procedures to process strings with the following requirements:

  • Create a procedure CountVowels that takes a string pointer in R0 and returns the number of vowels (a, e, i, o, u) in R0.
  • Use nested procedure calls where CountVowels calls a helper procedure IsVowel.
  • Follow AAPCS conventions for parameter passing and register usage.

Task 2: Factorial Calculation (Iterative) ​

Implement a procedure to calculate the factorial of a non-negative integer:

  • Create a procedure Factorial that takes a non-negative integer in R0 and returns its factorial in R0.
  • Use an iterative approach with a loop to compute the factorial.
  • Ensure proper handling of edge cases, such as 0! = 1.
  • Follow AAPCS conventions for parameter passing and register usage.

Task 3: Factorial Calculation (Recursive) ​

Implement a recursive version of the factorial calculation:

  • Create a procedure FactorialRec that takes a non-negative integer in R0 and returns its factorial in R0.
  • Use recursion to compute the factorial, ensuring proper base case handling.
  • Manage the stack appropriately to save and restore registers as needed.
  • Follow AAPCS conventions for parameter passing and register usage.
  • Test the procedure with various inputs to verify correctness.