-1

This code converts 1 digit hexadecimal to decimal, it's working, copy the internet, but I want to understand a little better how it works, and add a loop where I can get up to 4 digits.I would like a help on how to perform this loop.

I'm using masm16 and DosBox.

    .model small
.stack 100h
.data
msg1 db 10,13,'ENTER A HEX DIGIT:$'
msg2 db 10,13,'IN DECIMAL IS IT:$'
msg3 db 10,13,'DO YOU WANT TO DO IT AGAIN?$'
msg4 db 10,13,'ILLEGAL CHARACTER- ENTER 0-9 OR A-F:$'

.code

again:

   mov ax,@data
   mov ds,ax
   lea dx,msg1
   mov ah,9
   int 21h

   mov ah,1
   int 21h

   mov bl,al

   jmp go

go:

   cmp bl,'9'
   ja hex
   jb num
   je num

 hex:

    cmp bl,'F'
    ja illegal

   lea dx,msg2
   mov ah,9
   int 21h

    mov dl,49d
    mov ah,2
    int 21h

    sub bl,17d
    mov dl,bl
    mov ah,2
    int 21h

    jmp inp

 inp:

    lea dx,msg3
    mov ah,9
    int 21h

    mov ah,1
    int 21h

    mov cl,al
    cmp cl,'y'
    je again
    cmp cl,'Y'
    je again
    jmp exit

 num:

   cmp bl,'0'
   jb illegal

   lea dx,msg2
   mov ah,9
   int 21h

   mov dl,bl
   mov ah,2
   int 21h

   jmp inp

 illegal:

       lea dx,msg4
       mov ah,9
       int 21h

       mov ah,1
       int 21h

       mov bl,al

       jmp go

exit:
end
Daniel Schiramm
  • 11
  • 1
  • 1
  • 2
  • I tried to run but a strange error is occurring. Assembling: hextodec.asm hextodec.asm(13): error A2085: instruction or register not accepted in current CPU mode hextodec.asm(40): error A2085: instruction or register not accepted in current CPU mode hextodec.asm(50): error A2085: instruction or register not accepted in current CPU mode hextodec.asm(53): error A2081: missing operand after unary operator hextodec.asm(169): fatal error A1008: unmatched macro nesting – Daniel Schiramm Nov 16 '16 at 23:48
  • I researched on leea being equivalent to mov with offset, but it seems to have an error in the declaration of str, the errors continue. Assembling: hextodec.asm hextodec.asm(11): error A2085: instruction or register not accepted in current CPU mode - hextodec.asm(38): error A2085: instruction or register not accepted in current CPU mode - hextodec.asm(48): error A2085: instruction or register not accepted in current CPU mode - hextodec.asm(76): error A2085: instruction or register not accepted in current CPU mode - hextodec.asm(95): error A2150: word register cannot be first operand - 158 – Daniel Schiramm Nov 17 '16 at 23:09
  • I replaced it, now just an error now in the SHL AX, 4. hextodec.asm (95) error A2150: word register can not be first operand – Daniel Schiramm Nov 18 '16 at 12:29
  • We can separate `SHL AX,4` into four shifts : `shl ax,1` , `shl ax,1` , `shl ax,1` , `shl ax,1`. Also you can replace previous with : `sal ax,1` , `sal ax,1` , `sal ax,1` , `sal ax,1`. `shl` is "shift logical left", `sal` is "shift arithmetic left", both are synonyms. – Jose Manuel Abarca Rodríguez Nov 18 '16 at 15:02
  • If `shl ax,1` doesn't work, tell me if `shl al,1` works. If `shl al,1` works then we can not shift `ax`, but we can shift `al` and `ah` separately. I will wait until you tell me if `shl al,1` works to try this way. – Jose Manuel Abarca Rodríguez Nov 18 '16 at 15:07
  • Daniel, forget about my two previous comments, I did the change and **updated my answer** (also replaced "str" with "buffer" everywhere). If `SHL AX,4` is the problem, I replaced it with 4 consecutive `shl al,1` `rcl ah,1`, this change is enclosed between two thick lines `;■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■` so you can see where it is (you can remove the thick lines in your code). – Jose Manuel Abarca Rodríguez Nov 18 '16 at 15:26
  • Many thanks, Jose. It worked. Acho que poderíamos ter conversado em português. kkkk – Daniel Schiramm Nov 18 '16 at 23:19
  • Oops. I'm costarrican, I speak spanish, but I hope I will learn portuguese someday ^_º – Jose Manuel Abarca Rodríguez Nov 19 '16 at 17:57

1 Answers1

1

I found an old program that does what you need but it is very different than yours. I will paste it here because it could help you. I added some code of yours and made some other changes. This is how it works:

  • Capture hex number as string using int 21h ah=0Ah (not char by char).
  • Convert hex-string to a number in AX. Validate each char.
  • Convert AX to string to display it converted to decimal.
  • Ask user if wants to do it again.

Here is the code, just copy-paste and run:

.model small
.stack 100h
.data

msg1 db 10,13,10,13,'ENTER 1 TO 4 HEX DIGITS:$'
msg2 db 10,13,'IN DECIMAL IS IT:$'
msg3 db 10,13,10,13,'DO YOU WANT TO DO IT AGAIN (Y/N)?$'
msg4 db 10,13,'ILLEGAL CHARACTER- ENTER 0-9 OR A-F:$'

hex  db 5,?,5 dup(?) ;VARIABLE WITH 3 SECTIONS.
buffer  db 6 dup('$') ;RESULT COULD HAVE 5 DIGITS.

.code
  mov  ax, @data
  mov  ds, ax

again:

;CLEAR BUFFER (IN CASE IT HOLDS PREVIOUS RESULT).
  call clear_buffer

;DISPLAY 'ENTER 1 TO 4 HEX DIGITS:$'
  mov  ah, 9
  lea  dx, msg1
  int  21h

;CAPTURE HEX NUMBER AS STRING.
  mov  ah, 0ah
  lea  dx, hex
  int  21h

;CONVERT HEX-STRING TO NUMBER.
  lea  si, hex+2        ;CHARS OF THE HEX-STRING.
  mov  bh, [si-1]       ;SECOND BYTE IS LENGTH.
  call hex2number       ;NUMBER RETURNS IN AX.

;CONVERT NUMBER TO DECIMAL-STRING TO DISPLAY.
  lea  si, buffer
  call number2string    ;STRING RETURNS IN SI (BUFFER).

;DISPLAY 'IN DECIMAL IS IT:$'
  mov  ah, 9
  lea  dx, msg2
  int  21h            

;DISPLAY NUMBER AS STRING.
  mov  ah, 9
  lea  dx, buffer
  int  21h

illegal: ;JUMP HERE WHEN INVALID CHARACTER FOUND.

;DISPLAY 'DO YOU WANT TO DO IT AGAIN (Y/N)?$' 
  mov  ah, 9
  lea  dx, msg3
  int  21h

;CAPTURE KEY.
  mov  ah, 1
  int  21h
  cmp  al,'y'
  je   again
  cmp  al,'Y'
  je   again

;TERMINATE PROGRAM.  
  mov  ax, 4c00h
  int  21h 

;---------------------------------------------  
;FILL VARIABLE "BUFFER" WITH "$".
;EVERYTIME THE USER WANTS TO DO IT AGAIN, THE
;PREVIOUS RESULT MUST BE CLEARED.

clear_buffer proc
  lea  si, buffer
  mov  al, '$'
  mov  cx, 5  
clearing:
  mov  [si], al
  inc  si
  loop clearing

  ret
clear_buffer endp

;---------------------------------------------  
;INPUT  : BH = STRING LENGTH (1..4).
;         SI = OFFSET HEX-STRING.
;OUTPUT : AX = NUMBER.

hex2number proc
      MOV  AX, 0       ;THE NUMBER.
   Ciclo:
;■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
;     SHL  AX, 4       ;SHIFT LEFT LOWER 4 BITS.
;SHIFT LEFT AL AND AH MANUALLY 4 TIMES TO SIMULATE SHL AX,4.
      shl  al, 1
      rcl  ah, 1
      shl  al, 1
      rcl  ah, 1
      shl  al, 1
      rcl  ah, 1
      shl  al, 1
      rcl  ah, 1
;■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

      MOV  BL, [ SI ]  ;GET ONE HEX CHAR FROM STRING.

      call validate

      CMP  BL, 'A'     ;BL = 'A'..'F' : LETTER.
      JAE  letterAF    ;BL = '0'..'9' : DIGIT.
   ;CharIsDigit09.
      SUB  BL, 48      ;CONVERT DIGIT TO NUMBER.
      JMP  continue   
   letterAF:               
      SUB  BL, 55      ;CONVERT LETTER TO NUMBER.
   continue: 
      OR   AL, BL      ;CLEAR UPPER 4 BITS.
      INC  SI          ;NEXT HEX CHAR.
      DEC  BH          ;BH == 0 : FINISH.
      JNZ  Ciclo       ;BH != 0 : REPEAT.
   Fin:
      RET
hex2number endp

;---------------------------------------------  
;INPUT : BL = HEX CHAR TO VALIDATE.

validate proc
    cmp bl, '0'
    jb  error     ;IF BL < '0'
    cmp bl, 'F'
    ja  error     ;IF BL > 'F'
    cmp bl, '9'
    jbe ok        ;IF BL <= '9'
    cmp bl, 'A'
    jae ok        ;IF BL >= 'A'
error:    
    pop  ax       ;REMOVE CALL VALIDATE.
    pop  ax       ;REMOVE CALL HEX2NUMBER.
;DISPLAY 'ILLEGAL CHARACTER- ENTER 0-9 OR A-F$'
    mov  ah, 9
    lea  dx, msg4
    int  21h
    jmp  illegal  ;GO TO 'DO YOU WANT TO DO IT AGAIN (Y/N)?$'
ok:    
    ret
validate endp

;---------------------------------------------  
;INPUT : AX = NUMBER TO CONVERT TO DECIMAL.
;        SI = OFFSET STRING.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING.

number2string proc
  mov  bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
  mov  cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:       
  mov  dx, 0 ;NECESSARY TO DIVIDE BY BX.
  div  bx ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
  push dx ;PRESERVE DIGIT EXTRACTED FOR LATER.
  inc  cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
  cmp  ax, 0  ;IF NUMBER IS
  jne  cycle1 ;NOT ZERO, LOOP. 
;NOW RETRIEVE PUSHED DIGITS.
  lea  si, buffer
cycle2:  
  pop  dx        
  add  dl, 48 ;CONVERT DIGIT TO CHARACTER.
  mov  [ si ], dl
  inc  si
  loop cycle2  

  ret
number2string endp  

;------------------------------------------

end

Some explanation about int 21h ah=0Ah : this service requieres a variable with three sections:

hex  db 5          ;MAX LENGTH ALLOWED (4 CHARS).
     db ?          ;LENGTH ENTERED BY USER.
     db 5 dup(?)   ;STRING CHARS (PLUS ENTER AT THE END).

The first section is the maximum number of chars allowed (plus ENTER key at the end, which is char 0Dh), that's why if we want 4 chars we must define 5. The second section is the length entered by the user (defined after the user presses ENTER). The last section is the string itself with the chars entered by the user (and ENTER key at the end, this is char 0Dh).