Lab 5 - 64-Bit Assembly Language - Challenge

64-Bit Assembly Language

In this post, I'll share a challenge I took on: writing a program in AArch64 assembly to generate and display the times tables from 1×1 to 12×12 in a specific format.
Code with explanation comments:
.text
.globl _start

_start:
        mov     x20, 1                  // set right operand x20 to 1
        mov     x21, 10                 // load divisor 10 to x21 for calculating tens digit
        mov     x24, 100                // load divisor 100 to x24 for calculating hundreds digit

reset_left:
        mov     x19, 1                  // set left operand x19 to 1

loop:
        adr     x3, buffer              // load buffer address into x3

        mov     x4, x19                 // copy left operand to x4
        bl      convert_2digits2ch      // go to convert number to character function for left operand

        bl      space                   // store space to buffer
        mov     x4, 120                 // ASCII 120 is 'x'
        strb    w4, [x3], 1             // store 'x' character to buffer, then move to the next byte
        bl      space                   // store space to buffer

        mov     x4, x20                 // get a copy of right operand to x4
        bl      convert_2digits2ch      // go to convert number to character function for right operand

        bl      space                   // store space to buffer
        mov     x4, 61                  // ASCII 61 is '='
        strb    w4, [x3], 1             // store '=' character to buffer
        bl      space                   // store space to buffer

        mul     x4, x19, x20            // calculate result by x19 (left operand) * x20 (right operand)
        bl      convert_3digits2ch

        mov     x4, 10                  // ASCII 10 is '\n' character
        strb    w4, [x3]                // store '\n' character to buffer

        /* ===== Print ===== */
        mov     x0, 1                   // file descriptor: 1 is stdout
        adr     x1, buffer              // buffer location
        mov     x2, len                 // buffer length

        mov     x8, 64                  // write is syscall #64
        svc     0                       // invoke syscall
        /* ===== Print ===== */
        /* ===== Check left and right operand =====*/
        add     x19, x19, 1             // increase left operand by 1
        cmp     x19, 13                 // compare left operand if it reach 13
        b.lt    loop                    // if it is not 13, print next line
        add     x20, x20, 1
        cmp     x20, 13                 // compare right operand if it reach 13 if left operand is 13
        b.ge    exit                    // both left and right operands are 13. go to exit program
        /* ===== Print line =====*/
        mov     x0, 1                   // file descriptor: 1 is stdout
        adr     x1, line                // line location
        mov     x2, line_len            // line length

        mov     x8, 64                  // write is syscall #64
        svc     0                       // invoke syscall
        /* ===== Print line =====*/
        b       reset_left              // go to reset left operand
        /* ===== Check left and right operand =====*/
exit:
        mov     x0, 0                   // set exit status to 0
        mov     x8, 93                  // exit is syscall #93
        svc     0                       // invoke syscall

space:
        mov     x4, 32                  // ASCII 32 is space character
        strb    w4, [x3], 1             // store space character to buffer
        ret                             // return

convert_3digits2ch:
        udiv    x25, x4, x24            // x25 (hundreds) = x4 (number) / x24 (100). Get the hundreds digit
        msub    x4, x25, x24, x4        // x4 (remaining 2 digits) = x4 (number) - (x25 (hundreds) * x24 (100))
        mov     x26, x25                // make a copy (x26) of hundreds to check if it is a 3 digits number
        cmp     x25, 0                  // compare hundreds if it is 0
        b.ne    st_hundreds             // store hundreds digit if it is not 0
        mov     x25, 32                 // store space character if hundreds digit is 0
        strb    w25, [x3], 1            // store to buffer
        b       convert_2digits2ch      // go to convert the remaining 2 digits
st_hundreds:
        add     x25, x25, 48            // convert hundreds digit to character
        strb    w25, [x3], 1            // store to buffer
convert_2digits2ch:
        udiv    x22, x4, x21            // x22 (tens) = x4 (number) / x21 (10). Get the tens digit
        msub    x23, x22, x21, x4       // x23 (units) = x4 (number) - (x22 (tens) * x21 (10)). Get the units digit

        cmp     x26, 0                  // check if hundreds digit is 0
        b.ne    st_tens                 // if hundreds digit is not 0, store the tens digit no matter what it is
        cmp     x22, 0                  // if hundreds digit is 0, check if tens is 0
        b.ne    st_tens                 // if tens digit is not 0, store the tens digit
        mov     x22, 32                 // if tens digit is 0, store space instead
        strb    w22, [x3], 1            // store space to buffer
        b       st_units                // go to store units digit
st_tens:
        mov     x26, 0                  // reset x26
        add     x22, x22, 48            // convert tens digit to character
        strb    w22, [x3], 1            // store tens digit to buffer
st_units:
        add     x23, x23, 48            // convert units digit to character
        strb    w23, [x3], 1            // store units digit to buffer
        ret                             // return


.data
buffer: .space  14
len =   .-buffer
line:   .ascii "-------------\n"
line_len = .-line
Result:













Comments

Popular posts from this blog

Project - Stage 1: Create a Basic GCC Pass

Lab 4 - GCC Build