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 = .-lineResult:
Comments
Post a Comment