

main:
    lea si,hex_string
    mov ax,5150
    call itoa
    
    mov si,string
    call strlen    
    mov ax,bx
    lea si,[hex_string]
    call int2hex
    mov si,string
    call toupper
    jmp main
    
main_done:
    jmp main_done

;
; strlen
;
; Computes the length of a string with address passed in SI. Returns the length
; in BX
;
; NOTE: What happens if we pass a zero-length string?
;
strlen:
    mov bx,0             ; Initialize length of string to 0
strlen_loop:
    add bx,1             ; Increment the string length
    cmp byte [si+bx],0   ; Check if we have reached NULL terminator
    jne strlen_loop      ; If not, go back and check another character
    ret                  ; If NULL terminator reached, return to caller.

;
; int2hex
;
; Converts 16-bit integer in AX to a 4-byte NULL-terminated hex string pointed
; to by SI.
;
; NOTE: What if number is negative? What about if it has non-numeric characters?
;
int2hex:
    mov cx,16            ; Num bits to shift number by
int2hex_loop:
    sub cx,4             ; Decrement shift to move on the the next nibble
    mov bx,ax            ; Copy input number to BX
    shr bx,cl            ; Shift input right
    and bx,0xf           ; Mask off the low-order nibble
    add bx,'0'           ; Add the ASCII offset
    cmp bx,'9'           ; Check if digit is greater than 9
    jl int2hex_write_digit ; If not, move on
    add bx,7             ; If digit greater than 9, add offset to 'A'
int2hex_write_digit:
    mov [si],bx          ; Store the ASCII character to memory
    add si,1             ; Increment the string pointer
    test cx,cx           ; Check to see if we've gotten to lowest order nibble
    jne int2hex_loop     ; If not, keep going
    ret

;
; strrev
;
; Reverses a string, with pointer passed in SI
;
strrev:
    call strlen          ; Get string length in bx
    mov di,si            ; Get address of the string's NULL terminator in DI
    add di,bx
    dec di               ; Subtract 1 to get address of last char of string
strrev_loop:
    mov al,[si]          ; Get char from beginning of string in AL
    mov ah,[di]          ; Get char from end of string in AH
    mov [si],ah          ; Swap the two characters in the buffer
    mov [di],al
    inc si               ; Move the two pointers toward the middle of the string
    dec di
    cmp si,di            ; Figure out if the pointers have crossed
    jl strrev_loop       ; If not, keep going
    ret

; itoa
;
; Converts integer in AX to a base-10 string, pointed to by SI. Builds the
; string backwards (starting at the least significant digit) then reverses it.
;
itoa:
    mov di,si            ; Save pointer to beginning of string    
    mov bx,10            ; Put the base to divide by in BX
itoa_loop:
    xor dx,dx            ; Clear DX
    div bx               ; AX <- AX / BX with remainder in DX
    add dx,'0'           ; Add the ASCII offset
    mov [si],dl          ; Put the digit into the string buffer
    inc si               ; Increment the string pointer
    test ax,ax           ; Figure out if we've gotten a quotient of zero yet
    jne itoa_loop        ; If not, keep dividing
    mov [si],0           ; NULL-terminate the string
    mov si,di            ; Restore pointer to beginning of string
    call strrev          ; Reverse the string
    ret

;
; toupper
;
; Converts all characters in a NULL-terminated string to uppercase. Address of
; the start of the string passed in SI. Returns nothing.
;
; NOTE: What if there is a { or } or | character in the striung?
;
toupper:
    mov al,[si]          ; Read a character from the string into AL
    add si,1             ; Increment the address of the current character
    cmp al,0             ; Check if we have a NULL terminator
    je toupper_done      ; If NULL, we're done
    cmp al,'a'           ; Check if character is lower case
    jl toupper           ; If not, go get next character
    sub al,32            ; Otherwise, subtract offset between upper and lower
    mov [si-1],al        ; Save the new character in the correct position
    jmp toupper          ; And get the next character
toupper_done:
    ret
    
string:
    db "Neil is awesome!!!",0

hex_string:
    db 10 dup(0)
    
decimal_number:
    db "5150",0