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
Post a Comment