title: 8086 Assembly (TASM): Displaying an ASCII character value as HEX
body: <p>** Edited for clarification and "cleaner" code.</p>
  
  <p>I'm trying to accept a character from the keyboard (any character) and convert it's ASCII value to hex, then display it.  </p>
  
  <p>I know how to convert from base 10 to hex, but just to make sure I'm not using incorrect terminology:</p>
  
  <p>If I enter "c" in as my ASCII value, it's decimal value is 63.  63 divided by 16 (hex is base 16) = 3.9375.  Save the quotient of 3 for later.  Remainder * base (.9375 * 16) = 15.  15 is Hex character "F".  </p>
  
  <p>Quotient divided by base (3 / 16) = 0.1875.  Quotient is zero, so this is the last step in conversion.  Remainder * base (.1875 * 16) = 3</p>
  
  <p>Read them from last to first ("first in, last out", if thinking about the stack), and I get "3F" as the Hex value for the decimal number "63" (which is ASCII for "c")</p>
  
  <p>This is correct, yes?</p>
  
  <p>It's pretty simple to read, I hope.  I just get the character from the keyboard (AL), set BX as the divisor (base 16), and then divide AL by BX, store the remainder in the stack, and later on loop through the stack and try to display it...</p>
  
  <p>I think my problem is that something is wrong with my multiplication and with my INT 21H/02H.  I'm not sure if I need to add 30h in order to display the character or not...</p>
  
  <p>On top of that, I'm not even sure if I need to be at that point (displaying) yet anyway, because I still haven't figured out how to convert 10-15 to A-F for hex.  </p>
  
  <p>I tried speaking with my teacher, and after waiting 30 minutes for him to finish speaking to another gaggle of students in my class (about something from another one of his classes, and not this one...which irked me quite a bit), the most that I got was "start over".  </p>
  
  <p>When asked about "what about using SHR and SHL?" as it was pointed out to me, but I was told that it can be done without that, and that I can't use those commands (they haven't been covered in the class).</p>
  
  <p>Any input on what I'm doing wrong?  Thanks!</p>
  
  <pre><code>    CHAR2HEX PROC                   ; Accept a character, print it's ascii value in hex.
  
          MOV DX, OFFSET AskChar      ; Display prompt
          MOV AH, 09H
          INT 21H
  
          MOV AX, 0                   ; Clear AX
  
          MOV AH, 07H                 ; Get keyboard input w/ no echo (AL)
          INT 21H
  
          MOV BX, 16                  ; Set up the divisor (base 16)
          MOV CX, 0                   ; Initialize the counter
          MOV DX, 0                   ; Clear DX
  
          Divide:                         
                                      ; Dividend (what's being divided) in DX/AX pair, Quotient in AX, Remainder in DX.
              DIV BX                  ; Divide (will be word sized).
              PUSH AX                 ; Save DX (the remainder) to stack.
  
              ADD CX, 1               ; Add one to counter
  
              MOV DX, 0               ; Clear Remainder (DX)
              CMP AX, 0               ; Compare Quotient (AX) to zero
              JNE Divide              ; If AX not 0, go to "Divide:"
  
          Multiply:
                                      ; Multiply remainder (from stack) by 16 to get hex value.               
              MOV DX, 0               ; Clear DX           
              POP AX                  ; Get remainder from stack into AX.
  
              MUL BX                  ; Multiply AX * BX.  (DX= high order bits, AX = low order bits)
              MOV DX, AX
  
              SUB DL, 30h             ; ADD 30h to DL 
              MOV AH, 02h             ; 02h to display AH (DL)
              INT 21H                 ; Send to DOS
  
              LOOP Multiply           ; If more to do, Multiply again
                                      ; LOOP subtracts 1 from CX. If non-zero, loop.
              RET
      CHAR2HEX ENDP
  END START
  </code></pre>
  
  <p><em><strong></em> EDITED **</strong></p>
  
  <p>I finally got it!  I was able to get the program to return the hex value of the ascii char that was pushed on the keyboard, but it only worked if each remainder was 0 through 9.  It wouldn't display the A through F, and instead used colons, semicolons, etc...</p>
  
  <p>I looked at an Ascii/Deicmal/Hex chart online, and noticed that the characters 0 through 9 are 30h through 39h.  But character A (for hex 10) doesn't start until 40h.  So I changed the program so that if the value was greater than 39h, it added 7h to DL and THEN display it.  </p>
  
  <pre><code>    CHAR2HEX PROC                   ; Accept a character, print it's ascii value in hex.
  
          MOV DX, OFFSET AskChar      ; Display prompt
          MOV AH, 09H
          INT 21H
  
          MOV AH, 07H                 ; Get keyboard input w/ no echo (AL)
          INT 21H
  
          MOV CL, AL                  ; Copy user input (AL) to CL
          MOV AX, 0                   ; Clear AX (get rid of HO bits)
          MOV AL, CL                  ; Copy user input back into AL
  
          MOV BX, 16                  ; Set up the divisor (base 16)
          MOV CX, 0                   ; Initialize the counter
          MOV DX, 0                   ; Clear DX
  
          Div2:                         
                                      ; Dividend (what's being divided) in DX/AX pair, Quotient in AX, Remainder in DX.
              DIV BX                  ; Divide (will be word sized).
              PUSH DX                 ; Save DX (the remainder) to stack.
  
              ADD CX, 1               ; Add one to counter
              MOV DX, 0               ; Clear Remainder (DX)
              CMP AX, 0               ; Compare Quotient (AX) to zero
              JNE Div2              ; If AX not 0, go to "Div2:"
  
          getHex2:
              MOV DX, 0               ; Clear DX.
              POP DX                  ; Put top of stack into DX.
              ADD DL, 30h             ; Conv to character.
  
              CMP DL, 39h
              JG MoreHex2
  
          HexRet2:        
  
              MOV AH, 02h             ; 02h to display AH (DL)
              INT 21H                 ; Send to DOS
  
              LOOP getHex2            ; If more to do, getHex2 again
                                      ; LOOP subtracts 1 from CX. If non-zero, loop.
              JMP Skip2
          MoreHex2:
              ADD DL, 7h
              JMP HexRet2             ; Return to where it left off before adding 7h.
          Skip2:
              RET
      CHAR2HEX ENDP
  </code></pre>