0

I'm trying to do something that's supposed to be simple but it's hell on earth.

I have this data segment:

    dseg segment
A DB 12H
B DB 34H

dseg ends

The thing I need to do is to take the '2' from the '12' and exchange it with the '3' at the '34' meaning that in the end of the program it should be like this:

A DB 13H
B DB 24H

I know how to split the digits but I can't figure out how to make the exchange happen.

START:  MOV AX,DSEG
    MOV DS,AX
    MOV ES,AX
    
    mov ax,0
    mov cx,0
    mov bl,10H
    mov al,A
    div bl
    mov dx,ax
    mov ax,0
    mov al,B
    div bl
    
    endhere:
    mov ah,4ch
    int 21h

Picture of the registers after the above commands: my registers

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • You don't need division for powers of 2, just shift by 4 bits, or AND with `0x0f`. Hex is special because the base is a power of 2. (Unlike splitting numbers into *decimal* digits, where you do need division by 10.) – Peter Cordes Jul 21 '20 at 15:43
  • Do you mean that for split the digits i dont need to divide? –  Jul 21 '20 at 15:45
  • 1
    Yes. See [How to convert a binary integer number to a hex string?](https://stackoverflow.com/q/53823756) for an example of breaking up a number into 4-bit groups. You don't need to actually convert to ASCII hex digits, though, just look at the shift / rotate and AND. – Peter Cordes Jul 21 '20 at 15:46
  • I Dont think we understand each other, i need at the end that the value of A will be 13, and the value of B will be 24. therefore i do think i need to take the right digit from A and exchange it with the left digit of B –  Jul 21 '20 at 15:49
  • 1
    Yes, and you do that by treating these numbers as 2 chunks of 4 bits, using shifts and AND to isolate a 4-bit group. I wasn't saying how to use those algorithm building blocks to accomplish the task, just what building blocks to use (`shr` and `and`, not `div`). I did post an answer. IDK how much more complicated a "simpler" way would be, that didn't take advantage of loading both as a 16-bit integer, and basically doing bit-field extract / insert. – Peter Cordes Jul 21 '20 at 16:03

1 Answers1

4

You don't need the div instruction to divide by 16, just shift by 4 bits, or AND with 0x0f. Hex is special because the base is a power of 2. (Unlike splitting numbers into decimal digits, where you do need division by 10.)

Never use div where the divisor is known to be a power of 2, especially not an assemble-time constant.


The "clever" way to do this would be to do a word load to get both values, then rotate that word so the 2 (low nibble of A) and 3 (high nibble of B) are in the same byte. Swap them with a 4-bit rotate of that byte, then word rotate the opposite direction from the first to put nibbles back where they were, with the swap still done.

; A and B are known to be adjacent, so a 2-byte load from A gets B:A in AH:AL = AX

   mov  ax, word ptr [A]      ;  Z Y  X W   in MSB-first notation, AH then AL
          ;; In your case:       3 4  1 2   (Z and W are the 4-bit chunks we want to swap)

   rol  ax, 4                 ;  Y X  W Z   (rotate the extreme nibbles to share one byte)
   rol  al, 4                 ;  Y X  Z W   (swap halves of AL)
   ror  ax, 4                 ;  W Y  X Z   (undo the first rotate)
         ;; In your case:        2 4  1 3

   mov  word ptr [A], ax      ; and store back to memory

If we'd started with ror ax, 4 (or rol ax, 12), we could have used rol ah,4 because the pair we want to swap would be together in AH instead of AL. Swapping 4-bit halves of a register can be done with ROR or ROL, it doesn't matter.

If you're programming for original 8086 (without 186 features like immediate shift counts), put 4 in CL and use ror ax, cl or whatever.

We could have done this with 3 memory-destination rotates, but that would suck for efficiency compared to using a register.

If we'd needed to swap Y and W for example, you'd need an extra rotate step because no word rotate can bring them together into the same byte. And a different approach might be better, like a bithack using xor to swap only the high 4 bits between AH and AL (kind of like an xor-swap, but masking tmp values), before a word store of AX.


The "non-clever" way would be more complicated, basically doing bit-field extract / insert with shr and/or and al, 0x0f to extract, and or to insert (after clearing the destination bits with and).

If you understand rotates, and x86 endianness, the "clever" way is short enough that it's easy to understand and verify. But if not, shr, shl, and, and or are going to be your building blocks for.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Thanks Alot, my lecturer thought me to use div for this actions thanks again!! –  Jul 21 '20 at 16:06
  • 2
    @OsherRevach: `div` would be a appropriate if you wanted to swap the high *decimal* digit of one number with the low *decimal* digit of another. Because then the base isn't a power of 2 so conversion isn't free for binary numbers. Hopefully you're mis-interpreting something your lecturer said, because `div` is a terrible idea here: very slow and inconvenient. And it's not bit-manipulation. – Peter Cordes Jul 21 '20 at 16:14