Skip to main content

Exercises 14.7 Programming Exercises

1.

Write a program in assembly language that asks the user to enter an unsigned integer, adds \(1\) to the number, and displays the result.

Solution

The writeStr, readLn, newLine, uDecToInt, and uIntToDec functions have been provided earlier in the book. Here is the main function to solve this problem.

@ incrementDec.s
@ Prompts user for unsigned decimal number and adds 1 to it.
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Constants for assembler
        .equ    maxChars,11     @ max input chars
        .equ    inputString,-16 @ for input string
        .equ    outputString,-28 @ for output string
        .equ    locals,32       @ space for local vars

@ Constant program data
        .section .rodata
        .align  2
prompt:
        .asciz        "Enter an unsigned number up to 4294967294: "

@ The program
        .text
        .align  2
        .global main
        .type   main, %function
main:
        sub     sp, sp, 8       @ space for fp, lr
        str     fp, [sp, 0]     @ save fp
        str     lr, [sp, 4]     @   and lr
        add     fp, sp, 4       @ set our frame pointer
        sub     sp, sp, locals  @ for local vars
        
        ldr     r0, promptAddr  @ prompt user
        bl      writeStr
        
        add     r0, fp, inputString  @ place for user input
        mov     r1, maxChars    @ limit input size
        bl      readLn
        
        add     r0, fp, inputString  @ user input
        bl      uDecToInt       @ convert it
        
        add     r1, r0, 1       @ increment user's number
        add     r0, fp, outputString
        bl      uIntToDec
        
        add     r0, fp, outputString
        bl      writeStr
        bl      newLine
        
        mov     r0, 0           @ return 0;
        add     sp, sp, locals  @ deallocate local var
        ldr     fp, [sp, 0]     @ restore caller fp
        ldr     lr, [sp, 4]     @       lr
        add     sp, sp, 8       @   and sp
        bx      lr              @ return

promptAddr:
        .word    prompt
2.

Modify the uIntToDec function (Listing 14.6.1) that you used in Exercise 14.7.1 to use the mls instruction for computing the remainder.

Solution
@ uIntToDecMls.s
@ Converts an int to the corresponding unsigned
@ decimal text string.
@ Calling sequence:
@       r0 <- address of place to store string
@       r1 <- int to convert
@       bl uIntToDec
@ 2017-09-29: Bob Plantz
@ 2017-09-30: Use mls for remainder comp - Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Constant for assembler
        .equ    tempString,-40  @ for temp string
        .equ    locals,16       @ space for local vars
        .equ    zero,0x30       @ ascii 0
        .equ    NUL,0

@ The program
        .text
        .align  2
        .global uIntToDec
        .type   uIntToDec, %function
uIntToDec:
        sub     sp, sp, 24      @ space for saving regs
        str     r4, [sp, 0]     @ save r4
        str     r5, [sp, 4]     @      r5
        str     r6, [sp, 8]     @      r6
        str     r7, [sp, 12]    @      r7
        str     fp, [sp, 16]    @      fp
        str     lr, [sp, 20]    @      lr
        add     fp, sp, 20      @ set our frame pointer
        sub     sp, sp, locals @ for local vars
        
        mov     r4, r0          @ caller's string pointer
        add     r5, fp, tempString @ temp string
        mov     r7, 10          @ decimal constant
        
        mov     r0, NUL         @ end of C string
        strb    r0, [r5]
        add     r5, r5, 1       @ move to char storage

        mov     r0, zero        @ assume the int is 0
        strb    r0, [r5]
        movs    r6, r1          @ int to convert
        beq     copyLoop        @ zero is special case
convertLoop:
        cmp     r6, 0           @ end of int?
        beq     copy            @ yes, copy for caller
        udiv    r0, r6, r7      @ no, div to get quotient
        mls     r2, r0, r7, r6  @ the mod (remainder)
        mov     r6, r0          @ the quotient
        orr     r2, r2, zero    @ convert to numeral
        strb    r2, [r5]
        add     r5, r5, 1       @ next char position
        b       convertLoop
copy:
        sub     r5, r5, 1       @ last char stored locally
copyLoop:
        ldrb    r0, [r5]        @ get local char
        strb    r0, [r4]        @ store the char for caller
        cmp     r0, NUL         @ end of local string?
        beq     allDone         @ yes, we're done
        add     r4, r4, 1       @ no, next caller location
        sub     r5, r5, 1       @ next local char
        b       copyLoop
        
allDone:        
        strb    r0, [r4]        @ end C string
        add     sp, sp, locals  @ deallocate local var
        ldr     r4, [sp, 0]     @ restore r4
        ldr     r5, [sp, 4]     @      r5
        ldr     r6, [sp, 8]     @      r6
        ldr     r7, [sp, 12]    @      r7
        ldr     fp, [sp, 16]    @      fp
        ldr     lr, [sp, 20]    @      lr
        add     sp, sp, 24      @      sp
        bx      lr              @ return
3.

Write a program in assembly language that asks the user to enter a signed integer, adds \(1\) to the number, and displays the result.

Hint

This would be a good point to write two functions that will also be useful in subsequent chapters. One, getDecInt will read a signed decimal integer from the keyboard and convert it into int format. The other, putDecInt will convert an int into the signed decimal text string that represents it and write it on the screen. An important software engineering guideline is to reuse code, so you should use your readLn, writeStr, uDecToInt, and uIntToDec functions to implement getDecInt and putDecInt.

Solution
@ incrementSigned.s
@ Prompts user for signed decimal number and adds 1 to it.
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Constant program data
        .section .rodata
        .align  2
prompt:
        .asciz        "Enter a signed integer between -2147483648 and +2147483646: "

@ The program
        .text
        .align  2
        .global main
        .type   main, %function
main:
        sub     sp, sp, 8       @ space for fp, lr
        str     fp, [sp, 0]     @ save fp
        str     lr, [sp, 4]     @   and lr
        add     fp, sp, 4       @ set our frame pointer
        
        ldr     r0, promptAddr  @ prompt user
        bl      writeStr
        
        bl      getDecInt       @ convert it
        
        add     r0, r0, 1       @ increment user's number
        bl      putDecInt       @ print result
        bl      newLine
        
        mov     r0, 0           @ return 0;
        ldr     fp, [sp, 0]     @ restore caller fp
        ldr     lr, [sp, 4]     @       lr
        add     sp, sp, 8       @   and sp
        bx      lr              @ return

promptAddr:
        .word    prompt
@ getDecInt.s
@ Gets signed decimal integer from keyboard.
@ Calling sequence:
@       bl getDecInt
@ returns equivalent int
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Constants for assembler
        .equ    maxChars,12     @ max input chars
        .equ    inputString,-20 @ for input string
        .equ    locals,8        @ space for local vars

@ Useful source code constants
        .equ    POS,0
        .equ    NEG,1

@ The program
        .text
        .align  2
        .global getDecInt
        .type   getDecInt, %function
getDecInt:
        sub     sp, sp, 16      @ space for saving regs
                                @ (keeping 8-byte sp align)
        str     r4, [sp, 4]     @ save r4
        str     fp, [sp, 8]     @      fp
        str     lr, [sp, 12]    @      lr
        add     fp, sp, 12      @ set our frame pointer
        sub     sp, sp, locals  @ for the string
        
        add     r0, fp, inputString  @ place to store input
        mov     r1, maxChars    @ limit input length
        bl      readLn
        
        add     r0, fp, inputString  @ input string
        mov     r4, POS         @ assume postive int

        ldrb    r1, [r0]        @ get char
        cmp     r1, '-          @ minus sign?
        bne     checkPlus       @ no, check for plus sign
        mov     r4, NEG         @ yes, flag as neg
        add     r0, r0, 1       @ go to the number
        b       convert         @ and convert it
checkPlus:  
        cmp     r1, '+          @ plus sign?
        bne     convert         @ no, we're at the number
        add     r0, r0, 1       @ go to the number
convert:
        bl      uDecToInt
        
        cmp     r4, POS         @ positive int?
        beq     allDone         @ yes, we're done
        mvn     r0, r0          @ no, complement it
        add     r0, r0, 1       @ and finish negate       
allDone:        
        add     sp, sp, locals  @ deallocate local var
        ldr     r4, [sp, 4]     @ restore r4
        ldr     fp, [sp, 8]     @         fp
        ldr     lr, [sp, 12]    @         lr
        add     sp, sp, 16      @         sp
        bx      lr              @ return
@ putDecInt.s
@ Converts an int to the corresponding signed
@ decimal text string.
@ Calling sequence:
@       r0 <- int to print
@       bl putDecInt
@ 2017-09-29: Bob Plantz

@ Define my Raspberry Pi
        .cpu    cortex-a53
        .fpu    neon-fp-armv8
        .syntax unified         @ modern syntax

@ Constants for assembler
        .equ    decString,-20   @ for  string
        .equ    locals,8        @ space for local varsbr

@ Useful source code constants
        .equ    POS,0
        .equ    NEGBIT,0x80000000

@ The program
        .text
        .align  2
        .global putDecInt
        .type   putDecInt, %function
putDecInt:
        sub     sp, sp, 16      @ space for saving regs
                                @ (keeping 8-byte sp align)
        str     r4, [sp, 4]     @ save r4
        str     fp, [sp, 8]     @      fp
        str     lr, [sp, 12]    @      lr
        add     fp, sp, 12      @ set our frame pointer
        sub     sp, sp, locals  @ space for the string
        
        add     r4, fp, decString  @ place to store string
        mov     r1, '+          @ assume positive
        strb    r1, [r4]
        tst     r0, NEGBIT      @ negative int?
        beq     positive        @ no, go on
        mov     r1, '-          @ yes, need to negate
        strb    r1, [r4]
        mvn     r0, r0          @ complement
        add     r0, r0, 1       @ two's complement
positive:
        mov     r1, r0          @ int to convert
        add     r0, r4, 1       @ skip over sign char
        bl      uIntToDec

        add     r0, fp, decString  @ string to write
        bl      writeStr

        add     sp, sp, locals  @ deallocate local var
        ldr     r4, [sp, 4]     @ restore r4
        ldr     fp, [sp, 8]     @         fp
        ldr     lr, [sp, 12]    @         lr
        add     sp, sp, 16      @         sp
        bx      lr              @ return