Changing a 3D-array by replacing some of its words with the sum of the 5 words that follow

41 Views Asked by At

The given logical segment

 I1 db ?
 I2 db ?
 I3 db ?
 A1 dw 5 dup (6 dup (0fh,4 dup (0)))
 Data1 ends
  1. Create a segment of codes (for example, with the name Code1), in which to implement the following task: replace all words of the three-dimensional array A1 with values 0fh with the sum of of the following (by offset in the segment) 5 words by using the indices I1,I2,I3 (the values located at addresses I1,I2,I3).
  2. Create another logical data segment (for example, named Data2), in which set the directive A2 dw 5 dup (6 dup (0fh,4 dup (0)))
  3. Create another logical segment of codes (for example, with the name Code2), in which the task of step 1 is performed using chain commands to search for the value 0fh. After calculation, compare the values in arrays A1 and A2. Ensure unconditional transfer of control from segment Code1 to segment Code2 by using indirect intersegment control transfer.
  ;for MASM 5.00 translator
  ;for DOS
  
  .386
  .MODEL flat ; for MASM 5.00

I can't understand the logic in this task in assembly code.

My code:

    .386
Data1 segment
I1 db ?
I2 db ?
I3 db ?
A1 dw 5 dup (6 dup (0fh,4 dup (0)))
Data1 ends

Data2 segment
A2 dw 5 dup (6 dup (0fh,4 dup (0)))
Data2 ends

Code1   segment use16 
    assume  cs:Code1, ds:Data1
start: 

    mov [I1], 0
    mov [I2], 0
    mov [I3], 0
    mov ax, DATA1
    mov ds, ax

    L1:
        L2:
            L3:
                movzx ax, byte ptr [I1]
                imul bx, ax, 6*5*2      
                movzx ax, byte ptr [I2]
                imul ecx, ax, 5*2               
                xor esi,esi
                movzx ax, byte ptr [I3]
                mov si, ax          
                lea di, [ecx + esi*2]   
                cmp A1[bx+di],0fh
                jne NEXT
                mov ax,0
                add ax,[A1+bx+di+2]
                add ax,[A1+bx+di+4]
                add ax,[A1+bx+di+6]
                add ax,[A1+bx+di+8]
                add ax,[A1+bx+di+10]
                mov [A1+bx+di],ax
    NEXT:
        inc I3
        cmp I3, 5
        jle L3
        mov I3, 0
        inc I2
        cmp I2, 6
        jle L2
        mov I2, 0
        inc I1
        cmp I1, 5
        jle L1
    
    jmp far ptr start2 
Code1   ends


Code2   segment use16
        assume cs:Code2, ds:Data1, es:Data2

start2:
    mov      ax,data1      
    mov      ds,ax     
    mov      ax,data2        
    mov      es,ax     
    mov cx, 150d
    mov di, OFFSET A2
    mov ax, 0fh
    cld
L:
    repnz scasw
    sub di, 2
    xor dx,dx
    add dx,[A2+di+2]
    add dx,[A2+di+4]
    add dx,[A2+di+6]
    add dx,[A2+di+8]
    add dx,[A2+di+10]
    mov [A2+di],dx
    add di, 2
    dec cx
    cmp cx,0
    jg L
    mov si,OFFSET A1
    mov di,OFFSET A2
    cld
    repz cmpsw
    sub si, 2
    sub di, 2
    mov bx,A1[si]
    mov dx,A2[di]


    mov ax, bx
    sub ax, dx 
    mov ax,4c00h 
    int 21h
Code2 ENDS
 end start2
1

There are 1 best solutions below

0
Sep Roland On

The data

replace all words of the three-dimensional array A1 with values 0fh with the sum of of the following (by offset in the segment) 5 words by using the indices I1,I2,I3

To me at least, this sounds like you're not supposed to care about reading memory beyond the array. And that is how you have solved it too. I mention this because it will influence the outcome from comparing both arrays (A1 and A2); if the garbage that is in memory after the arrays is any different, then the repe cmpsw could be producing the wrong result.

Data1 segment
I1 db ?
I2 db ?
I3 db ?
A1 dw 5 dup (6 dup (0fh,4 dup (0)))
Data1 ends

Data2 segment
A2 dw 5 dup (6 dup (0fh,4 dup (0)))
Data2 ends

I'm assuming these data segments are 16-byte aligned, and with no guarantee about the padding at the end. I would suggest the following:

Data1 segment
I1 db 0
I2 db 0
I3 db 0
   db 0                              <<< Word-alignment for A1 array
A1 dw 5 dup (6 dup (15, 4 dup (0)))
   db 0                              <<< Filler for consistent results
Data1 ends

Data2 segment
A2 dw 5 dup (6 dup (15, 4 dup (0)))
   db 0                              <<< Filler for consistent results
Data2 ends

The first method

Your triple nested loops are doing too many iterations! When there are 5 elements in the row, the zero-based index in the I3 variable can range from 0 to 4. With a pair of instructions like cmp I3, 5 jle L3, you are allowing the invalid index 5 to be used. The same error is present for the other indexes.

mov [I1], 0
mov [I2], 0
mov [I3], 0
mov ax, DATA1
mov ds, ax

Where do you think that the CPU will store these zero bytes if you don't set up the DS segment register before these mov instructions that depend on DS are used?

Below is my rewrite of these nested loops. I have refrained from repeating the same calculations over and over again in the most inner loop, and I have chosen to use 8086 code only. I know that you can use x86 instructions in real address mode, but what I don't like is the ugly mix of 16-bit and 32-bit registers that you were using for no good reason:

L1:
  mov  al, 6*5*2
  mul  I1
  mov  di, ax            ; DI is offset to a plane (a plane of rows and columns)
L2:
  mov  al, 5*2
  mul  I2
  mov  si, ax            ; SI is offset to a row within a plane
L3:
  xor  bx, bx
  mov  bl, I3
  shl  bx, 1             ; BX is offset to an element within a row

  add  bx, si            ; Address of current element is A1+di+si+bx
  cmp  [A1+bx+di], 15
  jne  NEXT
  mov  ax, [A1+bx+di+2]
  add  ax, [A1+bx+di+4]
  add  ax, [A1+bx+di+6]
  add  ax, [A1+bx+di+8]
  add  ax, [A1+bx+di+10]
  mov  [A1+bx+di], ax
NEXT:
  inc  I3
  cmp  I3, 5
  jb   L3
  mov  I3, 0
  inc  I2
  cmp  I2, 6
  jb   L2
  mov  I2, 0
  inc  I1
  cmp  I1, 5
  jb   L1

The second method

When this repne scasw instruction stops because the count got exhausted, you must not start adding 5 subsequent words. You must exit from your L loop.
When this repne scasw instruction stops because it found the value 15, the DI register points to behind the find and the CX register contains the number of remaining items. It is wrong to use dec cx at the bottom of your loop!

add dx,[A2+di+2]
add dx,[A2+di+4]
add dx,[A2+di+6]
add dx,[A2+di+8]
add dx,[A2+di+10]
mov [A2+di],dx

These instructions are adding the address of the A2 array twice! Once through the initialization of DI with mov di, offset A2 and a second time through the mention of [A2+ ... in the addressing mode.

Below is my rewrite with corrections applied. Do note that it is not necessary to first subtract 2 from DI, and later add 2 to DI. It is much better to play with the offsets a bit. Offsets can be negative too, as in mov es:[di-2], ax:

  mov  ax, data1      
  mov  ds, ax     
  mov  ax, data2        
  mov  es, ax     
  mov  cx, 5*6*5
  mov  di, offset A2
  cld
L:
  mov  ax, 15
  repne scasw
  jne  Q
  mov  ax, es:[di]
  add  ax, es:[di+2]
  add  ax, es:[di+4]
  add  ax, es:[di+6]
  add  ax, es:[di+8]
  mov  es:[di-2], ax
  test cx, cx
  jnz  L
Q:

The check

mov si,OFFSET A1
mov di,OFFSET A2
cld
repz cmpsw

You forgot to initialize the CX register. The repz depends on it. Because your 'second method' had that erroneous dec cx, the repz cmpsw instruction may have seemed to work. However, the new corrected code will leave CX=0 and then the 'check' won't do any comparing at all! Simply add mov cx, 5*6*5. Also, you don't need to clear the direction flag again.

sub si, 2
sub di, 2
mov bx,A1[si]
mov dx,A2[di]
mov ax, bx
sub ax, dx 
mov ax,4c00h 
int 21h

Here also, these mov instructions are adding the addresses of the arrays twice! Once through the initialization of SI / DI and a second time through the mention of A1 / A2 in the addressing mode.
And of course better than subtracting 2 from the index registers, you should use the offset -2.
The result from calculating AX = BX - DX gets lost by overwriting AX with the function number to exit the program!

My suggestion that returns the difference in the DOS.Exitcode AL:

  mov  cx, 5*6*5
  mov  si, offset A1
  mov  di, offset A2
  repe cmpsw
  mov  al, [si-2]
  sub  al, es:[di-2]
  mov  ah, 4Ch 
  int  21h