1

I am a new programmer for Assembly on Winx64. I'm attempting to set up code that divides the values of one array in the values of another using the basic arithmetic from Assembly programming. The lab I couldn't finish is this:

enter image description here

Here is the code I tried to implement (which was placed in the Hyper-V Virtual Machine, sorry for any poor indentation I end up having):

TITLE DISPLAY
      .MODEL SMALL
      .386
      .STACK
      .DATA
S     EQU 12 ;size of arrays
X     BYTE 4, 16, 100, -116, -68, -104, 125, 60, 99, 33, 55, 77
Y     BYTE 2, 3, 4, -5, -6, -7, -8, -9, -10, 11, 12, 13
Q     BYTE 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0     ;quotient = X/Y
R     BYTE 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0     ;remainder = X/Y

;Address of X is _______:_______
;Address of Y is _______:_______
;Address of Q is _______:_______
;Address of R is _______:_______

      .CODE
MAIN  PROC FAR
      .STARTUP
      ;Program
      MOV ESI, 0       ;use ESI and index to arrays
      MOV CX, S       ;counter for loop

L1:   MOV AX, 0 ;clear the AX register
      MOV AL, [X+ESI] ;load dividend
      MOV BL, [Y+ESI]
      MOV DX, 0 ;clear the DX register
      IDIV AX ;divide X by Y
      MOV [Q+ESI], EAX    ;store quotient in Q
      INC ESI  ;increment index by 1
      LOOP L1
      .EXIT 
MAIN  ENDP
      END

The first issue I'm having is that Line 29 has Error A2070: Invalid Instruction Operands. The second issue is that I'm not sure whether the entirety of the code is correct along with the error. I believe I am able to find the values of X and Y (not Q and R particularly) in the memory of the debugger, but I'm having trouble assembling this code first.

Here is also an Excel except with the expected values for Q and R.

enter image description here

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Jordan Means
  • 41
  • 1
  • 5
  • Which line is line 29? – fuz Mar 13 '20 at 08:31
  • 1
    Are you *sure* `main` is supposed to be a `proc far`? That's not normal for masm / tasm even for 16-bit code (with `.model small` before `.386`) (e.g. [Using 32 bit registers in MASM without changing the default segment definition size](//stackoverflow.com/q/47941699)). Since you're apparently writing 16-bit code, why use ESI instead of SI? Even the image you're starting from is clearly doing that, which makes no sense to me. SI is a valid register for 16-bit addressing modes, but they're using CX not ECX so clearly they intend 16-bit mode. (32 or 64 would be easier to run on 64-bit Windows) – Peter Cordes Mar 13 '20 at 08:35
  • 1
    Anyway, that's not the problem - one obvious showstopper is that `idiv ax` divides DX:AX by AX. IDK why you think BL might be an implicit input for IDIV, but it's not. Also, you need to *sign* extend with `cwd`, not zero-extend the dividend before `idiv`. [8086 assembly on DOSBox: Bug with idiv instruction?](https://stackoverflow.com/a/43575674). Since this is .386 code, you can use movsx loads of bytes from memory into 16-bit registers like AX, before sign-extending AX into DX:AX. – Peter Cordes Mar 13 '20 at 08:39
  • 1
    Oh, probably your error is on the 32-bit `mov` store into an array of bytes. AL is the 8-bit low half of the 16-bit quotient you're calculating. BTW, it would make more sense to use 8-bit division, unless you're worried about a #DE fault in the corner case of `-128 / -1` – Peter Cordes Mar 13 '20 at 08:41
  • @fuz MOV [Q+ESI], EAX ;store quotient in Q – Jordan Means Mar 13 '20 at 08:41
  • 2
    @JordanMeans Recall that `Q` is an array of bytes but `EAX` is a dword. There is a type mismatch here. If the quotient fits into 8 bits, use `MOV [Q+ESI], AL`. Otherwise, change the data type of your array elements appropriately. – fuz Mar 13 '20 at 09:11
  • 1
    @fuz Thanks everyone! The code works as expected largely due to fuz's suggestion! Thank you all for all your help! – Jordan Means Mar 14 '20 at 07:02
  • @fuz I can't mark it as accepted because you commented as opposed to responding as an answer. I upvoted you though. – Jordan Means Mar 14 '20 at 16:35
  • @JordanMeans That's why I ask you to write up an answer yourself. After all, you figured out the solution to your problems. I merely gave you a tiny hint that helped you find the solution on your own. – fuz Mar 14 '20 at 16:53
  • @fuz Can you explain how to do so? I'm relatively new here. – Jordan Means Mar 15 '20 at 00:54
  • 1
    @JordanMeans Normally you should be able to add an answer to any question, including your own. However, this question has been closed so you are unable to add any answers for the moment. I'll try to get it reopened so you can write said answer. – fuz Mar 15 '20 at 08:13

1 Answers1

1

Alrighty. The issue, found out by fuz, is that I stored the quotient incorrectly.

TITLE DISPLAY
      .MODEL SMALL
      .386
      .STACK
      .DATA
S     EQU 12 ;size of arrays
X     BYTE 4, 16, 100, -116, -68, -104, 125, 60, 99, 33, 55, 77
Y     BYTE 2, 3, 4, -5, -6, -7, -8, -9, -10, 11, 12, 13
Q     BYTE 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0     ;quotient = X/Y
R     BYTE 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0     ;remainder = X/Y

;Address of X is _______:_______
;Address of Y is _______:_______
;Address of Q is _______:_______
;Address of R is _______:_______

      .CODE
MAIN  PROC FAR
      .STARTUP
      ;Program
      MOV ESI, 0       ;use ESI and index to arrays
      MOV CX, S       ;counter for loop

L1:   MOV AX, 0 ;clear the AX register
      MOV AL, [X+ESI] ;load dividend
      MOV BL, [Y+ESI]
      MOV DX, 0 ;clear the DX register
      IDIV AX ;divide X by Y
      MOV [Q+ESI], AL   ;store quotient in Q
      INC ESI  ;increment index by 1
      LOOP L1
      .EXIT 
MAIN  ENDP
      END

Jordan Means
  • 41
  • 1
  • 5