lab4 - 64 bit Assembly language Lab - Part 2

 This is the second part of the lab 4 for my course SPO600. I am continuing for my previous blog, part 1 of lab4 which can be found at this link - Lab4-Part-1


In the previous labs I covered three tasks in which I have to write the assembly language for aarch64 and x86_64 programs. We wrote the loop along with loop counter and printed the counter with each increment from 0 to 9. In this blog I am going to cover remaining tasks


Task 4: Extend code for aarch64 to loop up to 30 with 2 digits.

In this task, we have to update our previous code for aarch64 and extend the loop to 30 digits. In this, we have to print 2 digits instead of one for which in arrch64 we have to use two different registers to store first digit and second digit of the counter. I used udiv command to calculate quotient which is equivalent to first digit and stored it in a register. Then, I used msub command to calculate remainder, which is equivalent to the second digit and stored it in a another register. Then I added '0' to convert values in those registers to ascii number. After that, I stored both of the registered in their respective locations on the string using strb. Here is the updated code:

.text
.globl _start

min = 0                          /* starting value for the loop index; note that this is a symbol (constant), not a variable */
max = 31                         /* loop exits when the index hits this number (loop condition is i<max) */

_start:

        mov     x19, min
        mov     x21, 10

loop:

        /*Start of loop*/

        adr     x25, msg        /*setting the address of string*/

        udiv    x20, x19, x21   /*unsigned divide  - calculating first digit*/
        msub    x22, x21, x20, x19  /* calulating reminder - second digit */

        add     x20, x20, '0'
        strb    w20, [x25, 5]   /*writing first digit*/

        add     x22, x22, '0'
        strb    w22, [x25, 6]   /*writing second digit*/

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

        mov     x8, 64
        svc     0

        /*End of loop*/

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

        mov     x0, 0           /* status -> 0 */
        mov     x8, 93          /* exit is syscall #93 */
        svc     0               /* invoke syscall */

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

Here is the output of the above code after successful build:



Task 5: update task 4 to suppress the leading zero for single digits

In task 5, we have to modify the code from the task for to remove the zero for digits 0-9 so that our loop should print 0-30 instead of 00-30.


This can be done easily by adding a label. I added a label before the second writing the second digits so that I can skip the first digit. To accomplish this used cmp command to compare the register holding loop counter with register having value 10 and then I used another command b.lt to branch to the label if counter is less than 10 meaning there is single digit. Moreover, I slightly modified my msg string so that it can work according to above. mechanism. Here is the improved code:

.text
.globl _start

min = 0                          /* starting value for the loop index; note that this is a symbol (constant), not a variable */
max = 31                         /* loop exits when the index hits this number (loop condition is i<max) */

_start:

        mov     x19, min
        mov     x21, 10

loop:

        /*Start of loop*/

        adr     x25, msg        /*setting the address of string*/

        udiv    x20, x19, x21   /*unsigned divide  - calculating first digit*/
        msub    x22, x21, x20, x19  /* calulating reminder - second digit */

        cmp     x19, x21
        b.lt DoubleDigits

        add     x20, x20, '0'
        strb    w20, [x25, 5]   /*writing first digit*/

DoubleDigits:
        add     x22, x22, '0'
        strb    w22, [x25, 6]   /*writing second digit*/


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

        mov     x8, 64
        svc     0

        /*End of loop*/

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

        mov     x0, 0           /* status -> 0 */
        mov     x8, 93          /* exit is syscall #93 */
        svc     0               /* invoke syscall */

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

Here is the output:

Task 5. Repeat same code for x86_64

Now, in the second part of task 5, we have to write the similar code for the x86_64 platform.


I followed the similar procedure to modify the previous code and updated it to loop till 30. Instead using two separate commands like aarch64, I only used div command which calculated both quotient and remainders and stored them in rax and rdx registers. Now both of these registers hold the first and second digit of number. Just like in case of aarch64, I used label to skip the first digit, for comparison I used cmp and to jump to label, I used jl command. Here is the code:

.text
.globl    _start

min = 0                         /* starting value for the loop index; note that this is a symbol (constan*t), not a variable */
max = 31                        /* loop exits when the index hits this number (loop condition is i<max) */
ten = 10

_start:
        mov     $min,%r15           /* loop index */
        mov     $ten, %r10

loop:
        /*Start*/


        movq    %r15, %rax
        movq    $0, %rdx
        div     %r10


        cmp     %r10, %r15
        jl      digit

        addq    $'0', %rax
        movq    $msg + 5, %r11
        movb    %al, (%r11)

digit:

        addq    $'0', %rdx
        movq    $msg + 6, %r11
        movb    %dl, (%r11)

        movq    $len,%rdx                       /* message length */
        movq    $msg,%rsi                       /* message location */
        movq    $1,%rdi                         /* file descriptor stdout */
        movq    $1,%rax                         /* syscall sys_write */
        syscall

        /*End*/

        inc     %r15                /* increment index */
        cmp     $max,%r15           /* see if we're done */
        jne     loop                /* loop if we're not */

        mov     $0,%rdi             /* exit status */
        mov     $60,%rax            /* syscall sys_exit */
        syscall

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

Here is the output:


During this part, I learned about division in both platforms, in aarch64 we have to perform two different commands to calculate quotient and remainder separately whereas in x86_64 we can calculate both and store them in rax and rdx using a very simple command but for this we have to prepare those registers. I found division more simple for x86_64 but overall I like aarch64.


Comments

Popular posts from this blog

Review of 2 Open Source Softwares

Final Implementation of SPO600 Project - Stage III

Testing for Stage II for Project