64-Bit Assembly Language Lab 3 part-4
Tags: aarch64, assembler, coding, tables
Published: 2024-05-31 13:18:47

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

## 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
                 
```

## Walkthrough

### Data Section

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

```

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

```

- `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)

```

- 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]
```

- 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]
```

- `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]

```

- `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]

```

- `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]

```

- `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]

```

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

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

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