Files
assembly/x86_64/4_collatz.asm

125 lines
2.0 KiB
NASM

global _start
section .bss
NR_INPUT_BUFFER: resb 4
NR_INPUT_BUFFER_SIZE: equ 4
section .data
RQ_NR_STR: db 'Please give me a number (0-999): '
RQ_NR_STR_SIZE: equ $ - RQ_NR_STR
NR_STR: db '8'
NR_STR_SIZE: equ 1
ZERO_ASCII_VALUE: equ 48
NINE_ASCII_VALUE: equ 57
INPUT_BASE: equ 10
STDOUT: equ 1
section .text
_start:
; Write to STDOUT
mov rax, 1 ; = write
mov rdi, STDOUT
mov rsi, RQ_NR_STR
mov rdx, RQ_NR_STR_SIZE
syscall
; Read from STDIN
xor rax, rax ; 0 = read
xor rdi, rdi ; 0 = stdin
mov rsi, NR_INPUT_BUFFER
mov rdx, NR_INPUT_BUFFER_SIZE
syscall
; Parse number
mov rdi, NR_INPUT_BUFFER ; array to loop
dec rax
mov rsi, rax ; loop limit
call parseNR
mov rdi, rax
call collatz
mov rdi, rax
exit:
mov rax, 60
syscall
; int ParseNumber(char * p, size_t length)
; IN
; - rdi = ptr to byte array
; - rsi = length of said array (greater than 0)
; OUT
; - rax = resulting number => returns 0 if it cannot parse
parseNR:
xor r8, r8 ; loop variable
xor rcx, rcx ; sum
.loop_body:
mov rax, rcx
mov rcx, qword INPUT_BASE
mul rcx
mov rcx, rax
movzx rax, byte [rdi + r8]
; Check if the value is within ASCII numeric bounds
cmp al, byte ZERO_ASCII_VALUE
jb .exit_failure
cmp al, byte NINE_ASCII_VALUE
jnb .exit_failure
; Subtract zero to make it a number
sub al, byte ZERO_ASCII_VALUE
; Store the sum
add rcx, rax
inc r8
cmp r8, rsi
jb .loop_body
; Return the result
mov rax, rcx
jmp .exit
.exit_failure:
xor rax, rax
.exit:
ret
; int Collatz(int n)
; IN
; - rdi = number to "collatz"
; OUT
; - rax = number of "collatz" iterations it took to reach 0
collatz:
xor r9, r9 ; iteration count
.loop_start:
cmp rdi, qword 1
jbe .loop_exit
inc r9
; Is rdi odd?
mov rax, rdi
and rax, qword 1
cmp rax, qword 1
je .uneven_routine
;.even_routine:
shr rdi, 1 ; divide by two using right shift 1
jmp .loop_start
.uneven_routine:
mov rax, rdi
add rdi, rdi ; rdi + rdi
add rdi, rax ; rdi + rdi + rdi = 3 * rdi
inc rdi
jmp .loop_start
.loop_exit:
mov rax, r9
ret