0

For this project I am given a maze represented as an array of bytes that either contains 20h (empty space that can be moved into) or anything else (full space that cannot be moved into)

From the driver program I am given

x    pointer   si
y    pointer   di
dir  pointer   bx  E=1 S=2 W=3 N=4
maze pointer   bp

I have figured out how to modify the registers once I determine if a space is empty and have also calculated the offset into the maze at which the byte I'm testing resides.

The formula: (Y-1) * 30 + (X-1) calculates the offset of the byte I want to test into the array. 30 is the width of the maze.

So essentially I need to do something like

mov al, ds:[bp + ((Y-1) * 30 + (X-1))]

and then compare the byte stored in al from the maze with 20h to see if i can move to that position

my current code for this is: which works correctly

    mov    al, dl               ; move the y position being tested into the AL register
    dec    al                   ; decrement the AL register for the offset calculation
    mul    [value]              ; multiply the al register by 30 and store the product in ax
    add    al, dh               ; add the x position to the ax
    adc    ah, 0
    dec    ax                   ; decrement the ax register for the offset calculation
    push   si                   ; Preserve SI
    mov    si, ax               ; move the offset calculated inside of ax into si
    mov    al, ds:[bp + si]     ; access the maze using data segment override with offset si
    pop    si                   ; Restore SI
    cmp    al, 20h              ; position in the maze at the offset empty
    jne    testnext             ; yes jump to the exit function              

we are graded on efficiency and its noted that we could use "advanced indirect addressing to avoid doing all of this offset calculation in ax so if you know how that could be done i would be incredibly grateful.

here is the full code:

;---------------------------------------------------------------------
; Program:   nextval subroutine
;
; Function:  Find next mouse move in an array 15 by 30.
;            We can move into a position if its contents is blank ( 20h ).
;
; Input:     Calling sequence is:
;            x    pointer   si
;            y    pointer   di
;            dir  pointer   bx  E=1 S=2 W=3 N=4
;            maze pointer   bp
;
; Output:    x,y,dir modified in caller's data segment
;
; Owner:     Dana A. Lasher
;
; Date:      Update Reason
; --------------------------
; 11/06/2016 Original version
;
;
;---------------------------------------
         .model    small               ;64k code and 64k data
         .8086                         ;only allow 8086 instructions
         public    nextval             ;allow extrnal programs to call
;---------------------------------------


;---------------------------------------
         .data                         ;start the data segment
;---------------------------------------
value db 30
;---------------------------------------
         .code                         ;start the code segment
;---------------------------------------
; Save any modified registers
;---------------------------------------
nextval:
    push   cx                          ; save cx register
    push   ax                          ; save ax register
    push   dx                          ; save dx register
    mov    cl, 0                       ; set testing phase to 0 stored in ch
;---------------------------------------
; Code to make 1 move in the maze
;---------------------------------------

testnext:
    mov    ax, 0
    mov    dx, 0
    mov    dh, [si]
    mov    dl, [di]
    inc    cl                          ; increment the testing phase

direction:
    cmp    byte ptr [bx], 1            ; is the moving direction East
    je     goingeast                   ; yes, jump to the going east function
    cmp    byte ptr [bx], 2            ; is the moving direction south
    je     goingsouth                  ; yes, jump to the going south function
    cmp    byte ptr [bx], 3            ; is the moving direction west
    je     goingwest                   ; yes, jump to the going west function
    cmp    byte ptr [bx], 4            ; is the moving direction north
    je     goingnorth                  ; yes, jump to the going north function
    jmp    exit
;---------------------------------------
; Going East        Check order: N-E-S-W
;---------------------------------------
goingeast: 
    cmp    cl, 1                       ; is the testing phase phase 1
    je     checknorth                  ; yes, check to see if a move north is valid
    cmp    cl, 2                       ; is the testing phase phase 2
    je     checkeast                   ; yes, check to see if a move east is valid
    cmp    cl, 3                       ; is the testing phase phase 3
    je     checksouth                  ; yes, check to see if a move south is valid 
    cmp    cl, 4                       ; is the testing phase phase 4
    je     checkwest                   ; yes, check to see if a move west is valid 
    jmp    exit 
;---------------------------------------
; Going South       Check order: E-S-W-N
;---------------------------------------
goingsouth:
    cmp    cl, 1                       ; is the testing phase phase 1
    je     checkeast                   ; yes, check to see if a move east is valid
    cmp    cl, 2                       ; is the testing phase phase 2
    je     checksouth                  ; yes, check to see if a move south is valid 
    cmp    cl, 3                       ; is the testing phase phase 3
    je     checkwest                   ; yes, check to see if a move west is valid 
    cmp    cl, 4                       ; is the testing phase phase 4
    je     checknorth                  ; yes, check to see if a move north is valid
    jmp    exit 
;---------------------------------------
; Going West        Check order: S-W-N-E
;---------------------------------------
goingwest: 
    cmp    cl, 1                       ; is the testing phase phase 1
    je     checksouth                  ; yes, check to see if a move south is valid 
    cmp    cl, 2                       ; is the testing phase phase 2
    je     checkwest                   ; yes, check to see if a move west is valid 
    cmp    cl, 3                       ; is the testing phase phase 3
    je     checknorth                  ; yes, check to see if a move north is valid
    cmp    cl, 4                       ; is the testing phase phase 4
    je     checkeast                   ; yes, check to see if a move east is valid
    jmp    exit 
;---------------------------------------
; Going North       Check order: W-N-E-S
;---------------------------------------
goingnorth:
    cmp    cl, 1                       ; is the testing phase phase 1
    je     checkwest                   ; yes, check to see if a move west is valid 
    cmp    cl, 2                       ; is the testing phase phase 2
    je     checknorth                  ; yes, check to see if a move north is valid
    cmp    cl, 3                       ; is the testing phase phase 3
    je     checkeast                   ; yes, check to see if a move east is valid
    cmp    cl, 4                       ; is the testing phase phase 4
    je     checksouth                  ; yes, check to see if a move south is valid 
    jmp    exit 
;---------------------------------------
; Check East                X + 1 Y same
;---------------------------------------
checkeast:
    inc    dh                          ; incremement dh to the x position being tested
    mov    ch, 1                       ; update the testing direction ch to 1
 
    mov    al, dl               ; move the y position being tested into the AL register
    dec    al                   ; decrement the AL register for the offset calculation
    mul    [value]              ; multiply the al register by 30 and store the product in ax
    add    al, dh               ; add the x position to the ax
    adc    ah, 0
    dec    ax                   ; decrement the ax register for the offset calculation
    push   si                   ; Preserve SI
    mov    si, ax               ; move the offset calculated inside of ax into si
    mov    al, ds:[bp + si]     ; access the maze using data segment override with offset si
    pop    si                   ; Restore SI
    cmp    al, 20h              ; position in the maze at the offset empty
    jne    testnext             ; yes jump to the exit function
 
    inc    byte ptr [si]          ; update x position
    mov    byte ptr [bx], 1           ; update moving direction
    jmp    exit
;---------------------------------------
; Check South               X same Y + 1
;---------------------------------------
checksouth:
    inc    dl                          ; increment dl to the y position being tested
    mov    ch, 2                       ; update the testing direction ch to 2

    mov    al, dl           ; move the y position being tested into the AL register
    dec    al               ; decrement the AL register for the offset calculation
    mul    [value]          ; multiply the al register by 30 and store the product in ax
    add    al, DH           ; add the x position to the ax
    adc    ah, 0
    dec    ax               ; decrement the ax register for the offset calculation
    push   si               ; Preserve SI
    mov    si, ax           ; move the offset calculated inside of ax into si
    mov    al, ds:[bp + si] ; access the maze using data segment override with offset si
    pop    si               ; Restore SI
    cmp    al, 20h          ; position in the maze at the offset empty
    jne    testnext             ; yes jump to the exit function
 
    inc    byte ptr [di]          ; update x position
    mov    byte ptr [bx], 2           ; update moving direction
    jmp    exit
;---------------------------------------
; Check West                X - 1 Y same
;---------------------------------------
checkwest:
    dec    dh                          ; update dh to the x position being tested
    mov    ch, 3                       ; update the testing direction ch to 3

    mov    al, dl           ; move the y position being tested into the AL register
    dec    al               ; decrement the AL register for the offset calculation
    mul    [value]          ; multiply the al register by 30 and store the product in ax
    add    al, dh           ; add the x position to the ax
    adc    ah, 0
    dec    ax               ; decrement the ax register for the offset calculation
    push   si               ; Preserve SI
    mov    si, ax           ; move the offset calculated inside of ax into si
    mov    al, ds:[bp + si] ; access the maze using data segment override with offset si
    pop    si               ; Restore SI
    cmp    al, 20h          ; position in the maze at the offset empty
    jne    testnext             ; yes jump to the exit function

    dec    byte ptr [si]          ; update x position
    mov    byte ptr [bx], 3           ; update moving direction
    jmp    exit
;---------------------------------------
; Check North               X same Y - 1
;---------------------------------------
checknorth:
    dec    dl                          ; update dl to the y position being tested
    mov    ch, 4                       ; update the testing direction ch to 4

    mov    al, dl           ; move the y position being tested into the AL register
    dec    al               ; decrement the AL register for the offset calculation
    mul    [value]          ; multiply the al register by 30 and store the product in ax
    add    al, dh           ; add the x position to the ax
    adc    ah, 0
    dec    ax               ; decrement the ax register for the offset calculation
    push   si               ; Preserve SI
    mov    si, ax           ; move the offset calculated inside of ax into si
    mov    al, ds:[bp + si] ; access the maze using data segment override with offset si
    pop    si               ; Restore SI
    cmp    al, 20h          ; position in the maze at the offset empty
    jne    testnext             ; yes jump to the exit function
 
    dec    byte ptr [di]           ; update x position
    mov    byte ptr [bx], 4           ; update moving direction
    jmp    exit
;---------------------------------------
; Restore registers and return
;----------------d-----------------------
exit:

    ; here the dx and cx registers should still have the needed information
    pop    dx                          ; restore the dx register
    pop    ax                          ; restore the ax register
    pop    cx                          ; restore the cx register
    ret                                ; return
;---------------------------------------
    end    nextval
DomC
  • 13
  • 3

1 Answers1

2

Next snippet shaves off a few instructions.

  • Knowing that the maze has a width of 30, we can do without having to retrieve that value from memory.
  • We can hide the 1-based to 0-based conversion in the displacement field of the CMP instruction.
  • We can avoid push and pop, and still preserve the SI register.
    mov    al, 30
    mul    dl            <<< AX is too high by 30
    add    al, dh
    adc    ah, 0         <<< AX is too high by 30 + 1
    xchg   si, ax        ; Preserve SI and load index   
    cmp    byte ptr ds:[bp + si - 31], 20h
    mov    si, ax        ; Restore SI
    jne    testnext

In order to remove the costly multiplication on you can define a list containing 15 multiples of 30 and then pick one of those numbers based on the value in the Y coordinate that ranges from 1 to 15.

list  dw  0, 30, 60, 90, 120, ...
          ^  ^
          |  | if Y=2
          | if Y==1
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • An alternative to the table lookup: 30 is `32-2`. 8086 bit-shifts aren't great (1 cycle per count IIRC), but `(x<<5) - 2*x` is not too bad, including zero-extending into a 16-bit reg before the shift. Or `((x<<4) - x) * 2` is how GCC does it for `-mtune=pentium`. https://godbolt.org/z/rP335s5h6. (Have to play around some, and manually avoid use of `movzx` on some CPUs, although it's slow on Pentium so GCC avoids it. `-mtune=i386` uses movzx and LEA with scaled-index addressing) – Peter Cordes Mar 27 '21 at 23:32