DEV Community

Yukti Manoj Mulani
Yukti Manoj Mulani

Posted on

64-Bit Assembly Language Lab 3 part-4

Hello everybody I am back with the last part of Lab-3 which is some optional challenges on the assembler. So, lets get right into it.

In todays post we will be writing a program to print tables in the assembler. The exact spec goes like this.
Write a program in aarch64 assembly language to print the times tables from 1-12 (“1 x 1 = 1” through “12 x 12 = 144”).

The output looks like this.

[ymulani@aarch64-001 aarch64]$ ./tables
 1 x  1 =   1
 2 x  1 =   2
 3 x  1 =   3
 4 x  1 =   4
 5 x  1 =   5
 6 x  1 =   6
 7 x  1 =   7
 8 x  1 =   8
 9 x  1 =   9
10 x  1 =  10
11 x  1 =  11
12 x  1 =  12
 1 x  2 =   2
 2 x  2 =   4
 3 x  2 =   6
 4 x  2 =   8
 5 x  2 =  10
 6 x  2 =  12
 7 x  2 =  14
 8 x  2 =  16
 9 x  2 =  18
10 x  2 =  20
11 x  2 =  22
12 x  2 =  24
 1 x  3 =   3
 2 x  3 =   6
 3 x  3 =   9
 4 x  3 =  12
 5 x  3 =  15
 6 x  3 =  18
 7 x  3 =  21
 8 x  3 =  24
 9 x  3 =  27
10 x  3 =  30
11 x  3 =  33
12 x  3 =  36
 1 x  4 =   4
 2 x  4 =   8
 3 x  4 =  12
 4 x  4 =  16
 5 x  4 =  20
 6 x  4 =  24
 7 x  4 =  28
 8 x  4 =  32
 9 x  4 =  36
10 x  4 =  40
11 x  4 =  44
12 x  4 =  48
 1 x  5 =   5
 2 x  5 =  10
 3 x  5 =  15
 4 x  5 =  20
 5 x  5 =  25
 6 x  5 =  30
 7 x  5 =  35
 8 x  5 =  40
 9 x  5 =  45
10 x  5 =  50
11 x  5 =  55
12 x  5 =  60
 1 x  6 =   6
 2 x  6 =  12
 3 x  6 =  18
 4 x  6 =  24
 5 x  6 =  30
 6 x  6 =  36
 7 x  6 =  42
 8 x  6 =  48
 9 x  6 =  54
10 x  6 =  60
11 x  6 =  66
12 x  6 =  72
 1 x  7 =   7
 2 x  7 =  14
 3 x  7 =  21
 4 x  7 =  28
 5 x  7 =  35
 6 x  7 =  42
 7 x  7 =  49
 8 x  7 =  56
 9 x  7 =  63
10 x  7 =  70
11 x  7 =  77
12 x  7 =  84
 1 x  8 =   8
 2 x  8 =  16
 3 x  8 =  24
 4 x  8 =  32
 5 x  8 =  40
 6 x  8 =  48
 7 x  8 =  56
 8 x  8 =  64
 9 x  8 =  72
10 x  8 =  80
11 x  8 =  88
12 x  8 =  96
 1 x  9 =   9
 2 x  9 =  18
 3 x  9 =  27
 4 x  9 =  36
 5 x  9 =  45
 6 x  9 =  54
 7 x  9 =  63
 8 x  9 =  72
 9 x  9 =  81
10 x  9 =  90
11 x  9 =  99
12 x  9 = 198
 1 x 10 =  10
 2 x 10 =  20
 3 x 10 =  30
 4 x 10 =  40
 5 x 10 =  50
 6 x 10 =  60
 7 x 10 =  70
 8 x 10 =  80
 9 x 10 =  90
10 x 10 = 190
11 x 10 = 110
12 x 10 = 120
 1 x 11 =  11
 2 x 11 =  22
 3 x 11 =  33
 4 x 11 =  44
 5 x 11 =  55
 6 x 11 =  66
 7 x 11 =  77
 8 x 11 =  88
 9 x 11 =  99
10 x 11 = 110
11 x 11 = 121
12 x 11 = 132
 1 x 12 =  12
 2 x 12 =  24
 3 x 12 =  36
 4 x 12 =  48
 5 x 12 =  60
 6 x 12 =  72
 7 x 12 =  84
 8 x 12 =  96
 9 x 12 = 198
10 x 12 = 120
11 x 12 = 132
12 x 12 = 144
Enter fullscreen mode Exit fullscreen mode

The Code reveal

 .text
 .globl _start
 min = 1                          /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
 max = 13                         /* loop exits when the index hits this number (loop condition is i<max) */
 table = 1
 _start:
     mov     x19, min      //Initialize the multipler (row index)
     mov     x20, table    // initialise the multiplicand (Column index)
 loop:
     add        x15, x19, 0x30
     adr        x14, msg
     mov        x12, 10
     udiv       x13, x19, x12
     add        x16, x13, 0x30
     cmp        x16, 0x30
     b.eq       ones
     strb       w16, [x14]

 ones:
     adr        x14, msg+1
     msub       x13, x13, x12, x19
     add        x13, x13, 0x30
     strb       w13, [x14]

 tensTable:
     add        x15, x20, 0x30
     adr        x14, msg+5
     mov        x12, 10
     udiv       x13, x20, x12
     add        x16, x13, 0x30
     cmp        x16, 0x30
     b.eq       onesTable
     strb       w16, [x14]
 onesTable:
     adr        x14, msg+6
     msub       x13, x13, x12, x20
     add        x13, x13, 0x30
     strb       w13, [x14]

 hundredres:
     mul        x21, x19, x20
     adr        x14, msg+10
     mov        x12, 100
     udiv       x15, x21, x12
     add        x13, x15, 0x30
     cmp        x13, 0x30
     b.eq       tensres
     strb       w13, [x14]
 tensres:
     msub       x15, x15, x12, x21
     mul        x21, x19, x20
     adr        x14, msg+11
     mov        x12, 10
     udiv       x17, x15, x12
     add        x13, x17, 0x30
     cmp        x13, 0x30
     b.eq       onesres
     strb       w13, [x14]
 onesres:
     adr        x14, msg+12
     msub       x17, x17, x12, x15
     add        x17, x17, 0x30
     strb       w17, [x14]

     mov        X0, 1
     adr        x1, msg
     mov        x2, len

     mov        x8, 64
     svc        0

     add     x19, x19, 1
     cmp     x19, max
     b.ne    loop

     mov     x19, min
     mov     x13, ' '
     adr     x14, msg
     strb    w13, [x14]
     adr     x14, msg+10
     strb    w13, [x14]
     adr     x14, msg+11
     strb    w13, [x14]
     add     x20, x20, 1
     cmp     x20, max
     b.ne    loop

     mov     x0, 0           
     mov     x8, 93         
     svc     0               /* syscall */

.data
msg:    .ascii  " # x  # =   #\n"
len=    . - msg

Enter fullscreen mode Exit fullscreen mode

Walkthrough

Data Section

.data
msg:    .ascii  " # x  # =   #\n"
len=    . - msg

Enter fullscreen mode Exit fullscreen mode
  • msg is the format string used for printing each line of the multiplication table. It contains placeholders for the two numbers being multiplied and the result.
  • len is calculated as the length of the msg string.

Text Section

.text
.globl _start
min = 1
max = 13
table = 1

Enter fullscreen mode Exit fullscreen mode
  • min, max, and table are constants used for loop control.
  • The entry point _start is defined as a global label.

Start of the Program

_start:
     mov     x19, min      //Initialize the multipler (row index)
     mov     x20, table    // initialise the multiplicand (Column index)

Enter fullscreen mode Exit fullscreen mode
  • Initialize x19 with min (1), representing the starting row index.
  • Initialize x20 with table (1), representing the starting column index.

Main Loop

 loop:
     add        x15, x19, 0x30
     adr        x14, msg
     mov        x12, 10
     udiv       x13, x19, x12
     add        x16, x13, 0x30
     cmp        x16, 0x30
     b.eq       ones
     strb       w16, [x14]

 ones:
     adr        x14, msg+1
     msub       x13, x13, x12, x19
     add        x13, x13, 0x30
     strb       w13, [x14]
Enter fullscreen mode Exit fullscreen mode
  • The loop starts by converting the current row index x19 to a character.
  • adr x14, msg loads the address of the msg string into x14.
  • udiv x13, x19, x12 divides x19 by 10 to get the tens digit.
  • add x16, x13, 0x30 converts the tens digit to its ASCII representation.
  • cmp x16, 0x30 checks if the tens digit is zero.
  • If the tens digit is zero, it branches to the ones label.
  • Otherwise, it stores the tens digit in msg and proceeds.

Formatting Ones Digit for Row Index

ones:
     adr        x14, msg+1
     msub       x13, x13, x12, x19
     add        x13, x13, 0x30
     strb       w13, [x14]
Enter fullscreen mode Exit fullscreen mode
  • adr x14, msg+1 loads the address of the second character in msg.
  • msub x13, x13, x12, x19 calculates the remainder to get the ones digit.
  • add x13, x13, 0x30 converts the ones digit to its ASCII representation.
  • strb w13, [x14] stores the ones digit in msg.

Formatting Multiplier

tensTable:
    add        x15, x20, 0x30
    adr        x14, msg+5
    mov        x12, 10
    udiv       x13, x20, x12
    add        x16, x13, 0x30
    cmp        x16, 0x30
    b.eq       onesTable
    strb       w16, [x14]

onesTable:
    adr        x14, msg+6
    msub       x13, x13, x12, x20
    add        x13, x13, 0x30
    strb       w13, [x14]

Enter fullscreen mode Exit fullscreen mode
  • add x15, x20, 0x30 converts the multiplier x20 to a character.
  • adr x14, msg+5 loads the address of the character in msg where the multiplier should be placed.
  • udiv x13, x20, x12 divides x20 by 10 to get the tens digit.
  • add x16, x13, 0x30 converts the tens digit to its ASCII representation.
  • cmp x16, 0x30 checks if the tens digit is zero.
  • If the tens digit is zero, it branches to the onesTable label.
  • Otherwise, it stores the tens digit in msg.

Formatting Ones Digit for Multiplier

onesTable:
    adr        x14, msg+6
    msub       x13, x13, x12, x20
    add        x13, x13, 0x30
    strb       w13, [x14]

Enter fullscreen mode Exit fullscreen mode
  • adr x14, msg+6 loads the address of the sixth character in msg.
  • msub x13, x13, x12, x20 calculates the remainder to get the ones digit.
  • add x13, x13, 0x30 converts the ones digit to its ASCII representation.
  • strb w13, [x14] stores the ones digit in msg.

Formatting Result

hundredres:
    mul        x21, x19, x20
    adr        x14, msg+10
    mov        x12, 100
    udiv       x15, x21, x12
    add        x13, x15, 0x30
    cmp        x13, 0x30
    b.eq       tensres
    strb       w13, [x14]

tensres:
    msub       x15, x15, x12, x21
    mul        x21, x19, x20
    adr        x14, msg+11
    mov        x12, 10
    udiv       x17, x15, x12
    add        x13, x17, 0x30
    cmp        x13, 0x30
    b.eq       onesres
    strb       w13, [x14]

onesres:
    adr        x14, msg+12
    msub       x17, x17, x12, x15
    add        x17, x17, 0x30
    strb       w17, [x14]

Enter fullscreen mode Exit fullscreen mode
  • mul x21, x19, x20 calculates the product of the row and column indices.
  • adr x14, msg+10 loads the address where the result should start being placed in msg.
  • udiv x15, x21, x12 divides the product by 100 to get the hundreds digit.
  • add x13, x15, 0x30 converts the hundreds digit to its ASCII representation.
  • cmp x13, 0x30 checks if the hundreds digit is zero.
  • If the hundreds digit is zero, it branches to the tensres label.
  • Otherwise, it stores the hundreds digit in msg.

Formatting Tens and Ones Digit for Result

tensres:
    msub       x15, x15, x12, x21
    mul        x21, x19, x20
    adr        x14, msg+11
    mov        x12, 10
    udiv       x17, x15, x12
    add        x13, x17, 0x30
    cmp        x13, 0x30
    b.eq       onesres
    strb       w13, [x14]

onesres:
    adr        x14, msg+12
    msub       x17, x17, x12, x15
    add        x17, x17, 0x30
    strb       w17, [x14]

Enter fullscreen mode Exit fullscreen mode
  • These sections handle formatting the tens and ones digits for the result similarly to the previous sections.

Printing the Formatted Message

     mov        X0, 1
     adr        x1, msg
     mov        x2, len

     mov        x8, 64
     svc        0
Enter fullscreen mode Exit fullscreen mode
  • Prepares the syscall to write the message to the standard output.
  • mov X0, 1 sets the file descriptor to 1 (standard output).
  • adr x1, msg loads the address of the message.
  • mov x2, len sets the length of the message.
  • mov x8, 64 sets the syscall number for write.
  • svc 0 makes the syscall.

Loop Control

     add     x19, x19, 1
     cmp     x19, max
     b.ne    loop

     mov     x19, min
     mov     x13, ' '
     adr     x14, msg
     strb    w13, [x14]
     adr     x14, msg+10
     strb    w13, [x14]
     adr     x14, msg+11
     strb    w13, [x14]
     add     x20, x20, 1
     cmp     x20, max
     b.ne    loop
Enter fullscreen mode Exit fullscreen mode
  • add x19, x19, 1: Increment the row index (x19).
  • cmp x19, max: Compare the current row index (x19) with the maximum limit (max, which is 13).
  • b.ne loop: If x19 is not equal to max, branch back to loop.
  • mov x19, min: Reset the row index (x19) to the minimum value (min, which is 1).
  • Insert spaces in the msg string to create a visual spacer between tables.
  • add x20, x20, 1: Increment the column index (x20).
  • cmp x20, max: Compare the current column index (x20) with the maximum limit (max).
  • b.ne loop: If x20 is not equal to max, branch back to loop.
  • If both row and column indices reach their maximum limits, the loop exits, and the program proceeds to termination.

So, that is it I wont talk much after this long and boring blog of walkthroughs and explainations. I hope you enjoyed it.

Until next time Happy Coding!!!!

Top comments (0)