0

For example, I input 1995.

In the memory, that's stored as 31 39 39 35, the ASCII for 1995.

Then I convert it to hex so it becomes separated into 13 5F (19 95). Code used is

mov ax, [memory location of first two bytes]
sub ax, 3030
aad

My question is, what do I do to make it 07CB, the real equivalent of 1995, instead of 13 5F which is 19 and 95 separately? What I want to do is work with 1995 as a year, i.e. subtract or add from it.

  • The maximal height of a 16 bit value is decimal 65535 and if we want to convert exactly this value for example into a 16 bit register, then we have to multiplcate the first highest converted ASCII with the value of decimal 10000 and the second highest ASCII with 1000 and so on and finally we have to add all values together. – Dirk Wolfgang Glomp Jul 01 '14 at 00:10
  • Now i am not sure if you want to get an output of a decimal or a hexadecimal value or simple if you want to get only the value into a 16 bit register. My answer shows only for to get a hexadecimal output. I hope that it is what you want to know. – Dirk Wolfgang Glomp Jul 01 '14 at 00:23

3 Answers3

0

I have splitted the job into two different parts. One part for to convert the decimal ASCII (with a base ten value system) into the AX-register, with multiplication and adding the values together. And the other part for to convert the value in AX into hexadecimal ASCIIs and with storing the result in a reserved memory location. Here is a code example of the second part:

ASCII     DB "0000", "$"

   mov  di, OFFSET ASCII
   mov  cl, 4
A: rol  ax, 4
   mov  bl, al
   and  bl, 0Fh             ; only low nibble of byte
   add  bl, 30h
   cmp  bl, 39h             ; avove "9"
   jna short B
   add  bl, 7               ; then letter from "A" to "F"
B: mov  [di], bl
   inc  di
   dec  cl
   jnz A

This routine can simple be enhance for 32 bit register. Just use "mov cl,8" + "A: rol eax,4" + ASCII DB "00000000","$" and also simple be reduce for 8 bit register for to get only 2 ASCIIs.

  • Ummm, well... You're converting a value in `AX` to a 4 digit hex ASCII output stored in `[ASCII]`. Nicely done, but OP is looking to convert ASCII decimal digits (in `[ASCII]`) to value (in `AX`) to use in calculations. You've got a very nice __value -> ASCII HEX__ routine there though. Well done! – lornix Jul 01 '14 at 09:46
  • I think i have explained the way for to convert ASCII decimal digits (in [ASCII]) to value (in AX) enough and i think "user3044500" can program it self now and if this new routine does not work correct, then it is possible to ask again with showing this new routine for help. – Dirk Wolfgang Glomp Jul 01 '14 at 11:03
0

I am going to assume you have stored the 5 CHARACTERS ('1','9','9','5','$') in the buffer named 'ASCII' (remember, 5 chars, including the terminating '$' byte, we need that!)

ASC2DEC:
    mov si, offset ASCII # this is where we get characters from
    mov cx, 0       # zero register to hold final result
cvtchar:
    mov al, [si]    # get a character (30-39 representing 0-9, right?)
    cmp al, '$'     # are we done?
    jz  cvtdone     # zero byte! (told you we needed that!)
    add cx, cx      # cx = cx * 2
    mov cx, bx      # bx = cx
    add cx, cx      # cx = cx * 2 (so now cx = cx * 4 overall)
    add cx, cx      # cx = cx * 2 (so now cx = cx * 8 overall)
    add cx, bx      # cx = cx + bx (so now cx = cx * 10 overall)
    inc si          # increment our pointer for next time
    and ax, 0Fh     # isolate the low nybble with the value (and zero rest of ax!)
    add cx, ax      # add new value to the final result
    jmp cvtchar     # do it again!
cvtdone:
    mov ax, cx      # obtain result in ax

We read each character, strip off the last nybble (the 0-9 part), and add that to our final result after multiplying by ten. We continue doing this until we reach the '$' delimiter. (a zero is more typical, but you're learning, so use whatever you want! yay!)

A walkthrough...

ASC2DEC:
    si = offset ASCII
    cx = 0

cvtchar:
    al = [si]     # = '1' = 31h
    al == '$'?    # nope!
    cx = cx * 10  # essentially shift cx left one digit (right?) (and 0 * 10 = 0!)
    si = si + 1   # bump pointer
    ax = ax & 0fh # & = AND, so now ax = 1 (note how we skillfully zeroed rest of ax!)
    cx = cx + ax  # cx == 1!
    jmp back to cvtchar...

cvtchar:
    al = [si]     # al = '9' = 39h
    al == '$'?    # nope!
    cx = cx * 10  # so cx now = 1 * 10 = 10
    si = si + 1   # bump pointer
    ax = ax & 0fh # ax = 9
    cx = cx + ax  # cx = 19
    jmp to cvtchar for another loop...

cvtchar:
    al = [si]     # al = '9' = 39h
    al == '$'?    # nope!
    cx = cx * 10  # cx = 190
    si = si + 1   # bump pointer
    ax = ax & 0fh # ax = 9
    cx = cx + ax  # cx = 199
    jmp to cvtchar (again!)

cvtchar:
    al = [si]     # al = '5' = 35h
    al == '$'?    # nope!
    cx = cx * 10  # cx = 1990
    si = si + 1   # bump pointer
    ax = ax & 0fh # ax = 5
    cx = cx + ax  # cx = 1995
    jmp to cvtchar (again!)

cvtchar:
    al = [si]     # al = '$' = 24h
    al == '$'?    # YES!
    jmp cvtdone

cvtdone:
    ax = cx       # get our final result in ax (1995!)

Now I imagine someone is going to ping me about doing the wacky adding to multiply cx by 10, but it's easier to repeatedly add cx (and bx) to get the result than to manipulate ax and dx to use the mul 10 instruction... which would destroy our character held in al (the digit!) There are always other ways to do something. This works, it's understandable, doesn't involve warping the logic to keep the registers loaded with desired values and serves as an example of what you can do.

This routine doesn't have a particular limit, although it'll get weird for values above 65535. (2^16-1). Look up Integer Overflow to help understand why. But it'll handle any number of digits (well, up to 5!) as long as you terminate them with the '$' character.

It doesn't do negative values, and it'll give wacky results if any of the characters encountered are NOT digits (!%&$ will return 157, honest!). But that's a lesson for another day.

Of course, displaying the result is another topic... I've actually covered it nicely in another question somewhere, using nasm and 32 or 64 bit instructions (you're using 16 bit here), but the concepts are identical, as are most of the instructions too! Look here, here, and here.

Community
  • 1
  • 1
lornix
  • 1,946
  • 17
  • 14
0

The problem with your code is that the aad instruction expects the high order digit to be in ah and low order in al. Your mov ax instruction gets them in the wrong order. To fix this, try:

mov ax, [buf]
sub ax, 3030
xchg ah, al
aad             ; `al` now holds 10 * 1 + 9

To accumulate the full value 1995, you'd continue from here:

mov ah, 100
mul ah          ; `ax` now holds 1900
mov bx, ax      ; save
mov ax [buf+2]
sub ax, 3030
xchg ah, al
aad
add bx, ax      ; bx now holds 1995
Gene
  • 46,253
  • 4
  • 58
  • 96