title: Assembly TASM large model procedure (called from C) matrix loop
body: <p>Wrote a procedure in Assembly 8086, which will receive from C the following:</p>
  
  <pre><code>int *matrix[size], int size, int *num1, int *num2. 
  </code></pre>
  
  <p>I wrote it first as small model, it worked great, when I turned it to large model it stopped working correctly, I tried changing the loops count, the "rows pointer" add by 4, the "columns pointer" add by 2 (tried both add by 4 and the opposite).</p>
  
  <p>The procedure is supposed to check the minimum (in absolute value), meaning the smallest |x-y|.
  For example, the procedure will get N number, subtract it from all other numbers and always save the minimum of |x-y|. Afterwards it will move N one number ahead, and check the same with the rest of the numbers until all matrix have been checked.</p>
  
  <p>C Code (can't change anything in this one):</p>
  
  <pre><code>    #include &lt;stdio.h&gt;
      #include &lt;stdlib.h&gt;
  
      extern int getDiffMin(int *mat[], int size , int *num1 , int *num2);
  
          int main()
          {
              int 
  
  diff , i, j , num1 , num2;
          int **mat = (int **)malloc(sizeof(int *) * 4); 
          for (i = 0; i &lt; 4; i++)
              mat[i] = (int *)malloc(sizeof(int) * 4);
          for (i = 0; i &lt; 4; i++)
              for (j = 0; j &lt; 4; j++)
                  mat[i][j] = (i*j) - (5 * i) - (14 * j);
          for (i = 0; i &lt; 4; i++)
          {
              for (j = 0; j &lt; 4; j++)
                  printf("%d\t", mat[i][j]);
              printf("\n");
          }
          diff = getDiffMin(mat, 4 , &amp;num1 , &amp;num2);
          printf("\nminDiff == |(%d)-(%d)| = %d", num1 , num2 , diff);
          for (i = 0; i &lt; 4; i++)
              free(mat[i]);
          free(mat);
          return 0;
      }
  </code></pre>
  
  <p>Assembly code:</p>
  
  <pre><code>;extern int getDiffMin(int *mat[], int size , int *num1 , int *num2)
  ;                      BP+6+8      BP+10      BP+12+14    BP+16+18
  ;
  .MODEL LARGE ;Pointers size = 4 bytes
  .DATA
      I       DW  ?
      J       DW  ?
      N       DW  ?
      Min     DW  ?
      TempI   DW  ?
      TempJ   DW  ?
      Counter DW  ?
      Two     DW  2
  .CODE
  .386
  PUBLIC _getDiffMin
  _getDiffMin PROC FAR
  Start:
      PUSH BP ;Save BP's current value
      MOV BP,SP
      PUSH SI
      PUSH DI
      PUSH CX
      PUSH ES
      PUSH GS
      MOV CX,WORD PTR [BP+10] ;CX point to size (matrix of size*size)
      MOV SI,WORD PTR [BP+6] ;SI point to pointer in *mat[] (points to rows)
      MOV ES,WORD PTR [BP+8] ;Segment of *mat[]
      MOV DI,WORD PTR ES:[SI] ;DI point to value in *mat[] (points to columns, with first pointer on rows so gives value)
      MOV ES,WORD PTR ES:[SI+2] ;Segment of *mat[]
      MOV I,0 ;Rows index counter
      MOV J,0 ;Columns index counter
      MOV Counter,CX
      ADD Counter,CX ;Counter for loop
  FirstGetN: ;Get number to check with all other numbers
      MOV AX,WORD PTR ES:[DI] ;AX has value which DI is pointing to
      MOV N,AX
  FirstSubNumbers:
      ADD DI,2 ;Point to next column
      MOV AX,WORD PTR ES:[DI] ;AX has value one column ahead from N
      SUB AX,N
      CMP AX,0
      JG Continue1
      NEG AX ;Convert sub result to positive
  Continue1:
      MOV Min,AX ;Save minimum difference in Min for loop with compare ahead
      MOV SI,WORD PTR [BP+12] ;SI point to *num1 (in case first check had the minimum difference)
      MOV GS,WORD PTR [BP+14] ;Segment of *num1
      MOV AX,N
      MOV GS:[SI],AX ;*num1 = N
      MOV SI,WORD PTR [BP+16] ;SI point to *num2
      MOV GS,WORD PTR [BP+18] ;Segment of *num2
      MOV AX,WORD PTR ES:[DI] ;AX = second number
      MOV GS:[SI],AX ;*num2 = second number
  GetN:
      MOV SI,WORD PTR [BP+6] 
      MOV ES,WORD PTR [BP+8] 
      ADD SI,I ;Add needed row
      MOV DI,WORD PTR ES:[SI]
      MOV ES,WORD PTR ES:[SI+2]
      ADD DI,J ;Add needed column
      MOV AX,WORD PTR ES:[DI]
      MOV N,AX ;N contains number being checked with others
      MOV AX,I ;In order to move from N location forward (numbers before were checked during the loop)
      MOV TempI,AX
      MOV AX,J
      MOV TempJ,AX
      MOV AX,Counter
      CMP TempJ,AX ;Meaning it's in last column
      JE Fix
  AddJ:
      ADD TempJ,2 ;Move to next column
      JMP SubNumbers
  Fix:
      MOV TempJ,0 ;Back to first column
      ADD TempI,4 ;New row
  SubNumbers:
      MOV SI,WORD PTR [BP+6] 
      MOV ES,WORD PTR [BP+8] 
      ADD SI,TempI
      MOV DI,WORD PTR ES:[SI]
      MOV ES,WORD PTR ES:[SI+2]
      ADD DI,TempJ
      MOV AX,WORD PTR ES:[DI] ;AX contains number to check with N
      MOV BX,N ;Move N to BX in order to save N's value
      SUB BX,AX ;BX (N) -= AX
      CMP BX,0
      JG Continue2
      Neg BX
  Continue2:
      MOV AX,Min
      SUB AX,BX ;Substract former minimum and current sub result
      CMP AX,0 ;To check which one is bigger
      JLE Continue3 ;If BX &gt; AX 
      MOV Min,BX ;Else, Min=BX
      MOV SI,WORD PTR [BP+12] ;SI point to *num1
      MOV GS,WORD PTR [BP+14] ;Segment of *num1
      MOV AX,N
      MOV GS:[SI],AX ;*num1 = N
      MOV SI,WORD PTR [BP+16] ;SI point to *num2
      MOV GS,WORD PTR [BP+18] ;Segment of *num2
      MOV AX,WORD PTR ES:[DI] ;AX = second number
      MOV GS:[SI],AX ;*num2 = second number
  Continue3:
      MOV AX,Counter
      CMP TempJ,AX ;Meaning all columns were checked 
      JNE AddJ
      MOV TempJ,0 ;Else, go to first column
      ADD TempI,4 ;Next row
      MUL Two
      CMP TempI,AX ;Meaning all rows (and columns) were checked 
      JNE SubNumbers
      MOV AX,Counter
      ADD J,2 ;Move to next column with N number (J is pointing to INT so advance 2 bytes)
      CMP J,AX
      JNE GetN
  Fix2:
      MOV J,0
      MOV AX,Counter
      MUL Two
      ADD I,4
      CMP I,AX ;If all rows have been checked with N number (I is pointing to pointer so jumps of 4 byte, LARGE MODEL)
      JE Finish
      JMP GetN
  Finish:
      MOV AX,Min ;Save value to return
      POP GS ;POP by LIFO order
      POP ES
      POP CX 
      POP DI
      POP SI
      POP BP
      RET ;AX, IP and CS
  _getDiffMin ENDP
  END Start
  </code></pre>
  
  <p>Thank you.</p>