summaryrefslogtreecommitdiffstats
path: root/fizzbuzz.asm
diff options
context:
space:
mode:
authorGentoo <installgentoo@endianness.com>2021-03-27 09:44:50 +1100
committerGentoo <installgentoo@endianness.com>2021-03-27 09:44:50 +1100
commitf88388985dd557c3e71325b3f264c503b3610874 (patch)
tree559b59911d8893eb5364d116b260394671467f39 /fizzbuzz.asm
downloadfizzbuzz-asm-static-f88388985dd557c3e71325b3f264c503b3610874.tar.gz
fizzbuzz-asm-static-f88388985dd557c3e71325b3f264c503b3610874.tar.bz2
fizzbuzz-asm-static-f88388985dd557c3e71325b3f264c503b3610874.zip
initial commitHEADmaster
Diffstat (limited to 'fizzbuzz.asm')
-rw-r--r--fizzbuzz.asm141
1 files changed, 141 insertions, 0 deletions
diff --git a/fizzbuzz.asm b/fizzbuzz.asm
new file mode 100644
index 0000000..aaf5036
--- /dev/null
+++ b/fizzbuzz.asm
@@ -0,0 +1,141 @@
+; Version : 2.1
+; Last update : 25/5/2020
+; Description : FizzBuzz, but in assembly. Just a test of static memory usage.
+; Licence : GPLv3
+
+section .bss
+ Buff resb 422 ;Precalculated size
+ bufflen equ $-Buff
+
+section .data
+fizz db 'Fizz'
+buzz db 'Buzz'
+fizzbuzz db 'FizzBuzz'
+
+section .text
+global _start
+_start:
+xor r12,r12 ;counter register, set to count 0 to 100
+xor esi,esi ;used to store position in static memory
+xor r9,r9 ;r9 is used as a boolean to record if modulus 3 is achieved
+
+jmp skip ;skip incrementing the first time round so 0 is kept
+
+increment: inc r12 ;increment the counter
+skip: cmp r12,101 ;check if 100 has been reached
+jz exit ;exit if numbers 0 to 100 have been calculated and written to Buff
+
+check3: imul r8d,r12d,0xaaaaaaab;calculate modulus 3 quickly by multiplying the counter by 0xaaaaaaab and truncuating the result into r8d.
+cmp r8d,0x55555555
+ja check5 ;if r8d is larger than 0x55555555; (r12 % 3 !=0) and so modulus 5 is directly jumped to.
+
+;falls through if (r12 % 3 == 0)
+mov r9,1 ; set the fizz boolean to true
+
+check5: imul r8d,r12d,0xcccccccd ;calculate modulus 5 quickly by multiplying the counter by 0xcccccccd and truncuating the result into r8d.
+cmp r8d,0x33333333
+ja checkfizz ;if r8d is larger than 0x33333333; (r12 % 5 !=0). The state of fizz needs to be check to determine if anything needs printing.
+
+;; fall through if (r12 % 5 == 0)
+test r9,r9 ;r9 is the fizz boolean
+je buzzonly ;if there is no fizz, only print buzz
+
+;; fall through if both fizz and buzz are achieved; it's fizzbuzz time
+printfizzbuzz:
+mov rax,[fizzbuzz] ;copy fizzbuzz into rax
+mov qword[Buff+esi],rax ;copy fizzbuzz in rax into Buff
+add esi,8
+
+mov byte[Buff+esi], 0xA
+inc esi
+
+xor r9,r9 ;zero out the fizz boolean
+jmp increment
+
+checkfizz: test r9,r9 ;check if fizz is achieved
+je printnum ;if not, print current number
+
+;; fall through if fizz is achieved
+fizzonly:
+mov rax,[fizz] ;Copy 4 characters from fizz into rax
+mov qword[Buff+esi],rax ;Copy rax into Buff
+add esi,4 ;Increment Buff's pointer by 4 characters
+
+mov al,0xA ;Copy a newline into al (no need for static string usage)
+mov byte[Buff+esi], al ;write the newline into Buff
+inc esi ;increment Buff's pointer
+
+xor r9,r9 ;zero out the fizz boolean
+jmp increment
+
+buzzonly:
+mov rax,[buzz]
+mov qword[Buff+esi],rax
+add esi,4
+
+mov al,0xA ;Copy a newline into al (no need for static string usage)
+mov byte[Buff+esi], al
+inc esi
+
+jmp increment
+
+printnum:
+mov rax,r12 ;rax = counter
+mov r10,0xcccccccd ;used in division by 10 below
+
+xor edi,edi ;used to keep count of digits
+
+;;todo: Use a conversion method that doesn't print digits in the reverse order
+;; ecx=remainder = low digit = 0..9. eax/=10
+toascii_digit:
+mov ecx,eax ;copy eax to ecx for later usage in modulus.
+
+imul rax,r10 ;sign multiply rax by 0xcccccccd to complete the first step of division by 10
+shr rax,0x23 ;shift rax right by 35 to finish off rax/=10
+
+mov edx,eax ;move eax to edx so modulus can be done on it without clobbering eax
+lea edx,[rdx+rdx*4] ;multiply edx by 5 as the first step of modulus
+add edx,edx ;multiply edx by 2 as the second step of modulus
+sub ecx,edx ;subtract edx from the original number (before /=10) to finish off modulus 10
+
+;; the remainder(ecx) is the next calculated digit
+add ecx,'0' ;add 48 to ecx to turn it into the ASCII representation of the number
+mov byte[Buff+esi],cl ;shove cl(lower 8 bits in rcx) onto the stack
+inc esi ;write digits reversed...
+
+inc edi ;Count the number of digits generated
+
+test eax,eax
+jnz toascii_digit ;if eax does not equal zero, there are more ASCII chars to generate
+
+mov byte[Buff+esi],0xA ;Write a newline after the digits
+inc esi
+
+
+cmp edi,1
+ja two ;if above one digit check for two digits
+jmp increment ;One digit is in the correct order
+
+two:
+cmp edi,2
+ja exit ;above 2 characters won't work (sanely) for this method, so exit
+
+mov al,byte[Buff+esi-2] ;copy first digit to al
+mov cl,byte[Buff+esi-3] ;copy second digit to cl
+
+mov byte[Buff+esi-2],cl ;copy second digit over first digit
+mov byte[Buff+esi-3],al ;copy first digit over second digit
+
+jmp increment
+
+;;print Buff and exit
+exit:
+mov eax,1 ;sys_write
+mov edi,1 ;fp = stdout
+mov edx,bufflen ;length of Buff
+mov rsi,Buff ;Memory location of Buff
+syscall ;print all the bytes on the stack
+
+mov eax, 60 ;code for sys_exit
+xor edi, edi ;return value of 0
+syscall ;do sys_exit