Search code examples
arraysassemblyx86-16tasm

how to check if an arr is "wavy"?


my code should check if an ARR is "'wavy" which means the first element is less then the second, the second is greater then the third and same as this till the end of the arr.. but it doesn't work.. here is the code:

IDEAL
MODEL small
STACK 100h
DATASEG

        
ARR db 3 dup (?)
REZ db 1


CODESEG
start:
    mov ax,@data
    mov ds,ax
    mov cx,3                    ;cx=99
    xor ax,ax                    ; ax=0
    xor si,si                    ;si=0
    
    mov [ARR],0
    mov [ARR+1], 1
    mov [ARR+2], 0
    lea bx,[ARR]                 ; bx=offset arr
    L1: cmp cx,1
        je finish
        mov di,cx                ;di=cx (as index)
        neg di                   ;di=-di
        lea si,[bx+di] 
        mov ax,[3+si]
        cmp ax,[4+si]      ; compre the odd vs even index                                                   illegal use of register
        jg wrong                             ; exit if the odd index > even index
        dec cx                               ; cx=cx-1
        cmp cx,0                             ; check if cx=0
        je finish                            ; if  cx=0 finish
        mov di,cx                ;di=cx (as index)
        neg di                   ;di=-di
        lea si,[bx+di] 
        mov ax,[3+si]
        cmp ax,[4+si]        ; compre the even vs odd index                                                 illegal use of register
        jl wrong                            ; exit if the even <odd index
        loop L1                             ; cx=cx-1      if cx!=0 -> jump to L1
    wrong:
        mov [REZ],0
    finish:
    


exit:
    mov ax,4c00h
    int 21h
END start


there is even an example but it doesn't work..
do u know where is the mistake?

in the end we should end with res=1 if the arr is "wavy" or if it is not wavy arr=0


Solution

  • You have a mismatch between the size of the array elements (byte), and the size of the operations that you perform on these elements (word).

    The definition ARR db 3 dup (?) does not match the code mov ax,[3+si] cmp ax,[4+si]. You need to write mov AL, [3+si] cmp AL, [4+si] instead.

    When the loop ends, you should not fall-through into wrong, but rather jmp to exit.

    A single address register is enough:

      sub  cx, 1
      jbe  exit         ; In case of 0 or 1 array elements
      lea  si, [ARR]
      cld               ; Clear direction flag so LODSB will increment SI
    L1:
      lodsb
      cmp  al, [si]
      jg   wrong
      dec  cx
      jz   exit
      lodsb
      cmp  al, [si]
      jl   wrong
      loop L1
      jmp  exit
    wrong:
      ...
    exit:
      ...
    

    It is fascinating to explore alternative solutions

    • Using separate loops for the rising and falling edges of the sawtooth. Not only are the new loops very short, they can iterate over just one conditional branch thanks to sticking a sentinel to the end of the array. The sentinel is chosen such that the loop has got to end. The position where the loop exit occurs then decides about success or failure:

        mov  si, offset ARR         ; Address of the array
        mov  cx, ...                ; Number of array elements
        call TestWavy               ; -> AL=[0,1]
        mov  [REZ], al
      
        ...
      
      ; IN (cx,si) OUT (al) MOD (ah,bx,cx,dx,si,di)
      TestWavy:
        cld                         ; Clear DF so LODSW will SI++
        mov  bx, cx
        shr  bx, 1
        jz   .fine                  ; In case of 0 or 1 array elements
        lea  di, [si+bx]
        add  di, bx
        mov  dx, [di]               ; Preserve existing bytes
        mov  word ptr [di], 0102h   ; Sentinel for the rising edge
        push si                     ; (1)
      .rise:
        lodsw
        cmp  al, ah
        jng  .rise
        mov  [di], dx               ; Restore the bytes
        cmp  si, di
        pop  si                     ; (1)
        jbe  .wrong
      
        inc  si                     ; Address of the first falling edge
        dec  cx
        shr  cx, 1
        jz   .fine                  ; In case of 2 array elements
        mov  di, si
        add  di, cx
        add  di, cx
        mov  dx, [di]               ; Preserve existing bytes
        mov  word ptr [di], 0201h   ; Sentinel for the falling edge
      .fall:
        lodsw
        cmp  al, ah
        jnl  .fall
        mov  [di], dx               ; Restore the bytes
        cmp  si, di
        jbe  .wrong
      .fine:
        mov  al, 1
        ret
      .wrong:
        mov  al, 0
        ret
      
    • Using the byte-sized registers to the fullest. This minimizes the number of memory accesses as well as the number of iterations on the loop. Every iteration is guaranteed to be able to perform 8 comparisons, thanks to replicating the last element 7 times. The idea is, that this way, no early exits have to be included. And don't forget that you need to keep 7 unoccupied bytes after the array.

        mov  si, offset ARR         ; Address of the array
        mov  cx, ...                ; Number of array elements
        call TestWavy               ; -> AL=[0,1]
        mov  [REZ], al
      
        ...
      
      ; IN (cx,si) OUT (al) MOD (ah,bx,cx,dx,si,di,bp)
      TestWavy:
        sub  cx, 1
        jbe  .fine                  ; In case of 0 or 1 array elements
        cld                         ; Clear DF so LODSW will SI++
        mov  bp, cx                 ;         and STOSB will DI++
        lea  di, [si+bp]            ; Address of the last element
        mov  al, [di]
        mov  cx, 8
        rep stosb
      .more:
        lodsw                       ; Load 8 elements
        xchg dx, ax                 ; `mov dx, ax`
        lodsw
        xchg cx, ax                 ; `mov cx, ax`
        lodsw
        xchg bx, ax                 ; `mov bx, ax`
        lodsw
        cmp  dl, dh                 ; Check 4 rising edges
        jg   .wrong
        cmp  cl, ch
        jg   .wrong
        cmp  bl, bh
        jg   .wrong
        cmp  al, ah
        jg   .wrong
        cmp  dh, cl                 ; Check 4 falling edges
        jl   .wrong
        cmp  ch, bl
        jl   .wrong
        cmp  bh, al
        jl   .wrong
        cmp  ah, [si]
        jl   .wrong
        sub  bp, 8
        ja   .more
      .fine:
        mov  al, 1
        ret
      .wrong:
        mov  al, 0
        ret