*===========================================================================
* Copyright (c) 1990-1999 Info-ZIP.  All rights reserved.
*
* See the accompanying file LICENSE, version 1999-Oct-05 or later
* (the contents of which are also included in zip.h) for terms of use.
* If, for some reason, both of these files are missing, the Info-ZIP license
* also may be found at:  ftp://ftp.cdrom.com/pub/infozip/license.html
*===========================================================================
*
* match.s -- optional optimized asm version of longest match in deflate.c
* Written by Jean-loup Gailly
*
* Adapted for X68000 by NIIMI Satoshi <a01309@cfi.waseda.ac.jp>
* Adapted for the Amiga by Carsten Steger <stegerc@informatik.tu-muenchen.de>
* using the code in match.S.
* The major change in this code consists of removing all unaligned
* word accesses, because they cause 68000-based machines to crash.
* For maximum speed, UNALIGNED_OK can be defined.
* The program will then only run on 68020-based machines, though.


Cur_Match       reg     d0      ; Must be in d0!
Best_Len        reg     d1
Loop_Counter    reg     d2
Scan_Start      reg     d3
Scan_End        reg     d4
Limit           reg     d5
Chain_Length    reg     d6
Scan_Test       reg     d7
Scan            reg     a0
Match           reg     a1
Prev_Address    reg     a2
Scan_Ini        reg     a3
Match_Ini       reg     a4

MAX_MATCH       equ     258
MIN_MATCH       equ     3
WSIZE           equ     32768
MAX_DIST        equ     WSIZE-MAX_MATCH-MIN_MATCH-1


        .xref   _max_chain_length
        .xref   _prev_length
        .xref   _prev
        .xref   _window
        .xref   _strstart
        .xref   _good_match
        .xref   _match_start
        .xref   _nice_match


        .xdef   _match_init
        .xdef   _longest_match

        .text
        .even


_match_init:
        rts


_longest_match:
        move.l  4(sp),Cur_Match
.ifdef  UNALIGNED_OK
        movem.l d2-d6/a2-a4,-(sp)
.else
        movem.l d2-d7/a2-a4,-(sp)
.endif
        move.l  _max_chain_length,Chain_Length
        move.l  _prev_length,Best_Len
        lea     _prev,Prev_Address
        lea     _window+MIN_MATCH,Match_Ini
        move.l  _strstart,Limit
        move.l  Match_Ini,Scan_Ini
        add.l   Limit,Scan_Ini
        subi.w  #MAX_DIST,Limit
        bhi.b   limit_ok
        moveq   #0,Limit
limit_ok:
        cmp.l   _good_match,Best_Len
        bcs.b   length_ok
        lsr.l   #2,Chain_Length
length_ok:
        subq.l  #1,Chain_Length

.ifdef  UNALIGNED_OK
        move.w  -MIN_MATCH(Scan_Ini),Scan_Start
        move.w  -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
.else
        move.b  -MIN_MATCH(Scan_Ini),Scan_Start
        lsl.w   #8,Scan_Start
        move.b  -MIN_MATCH+1(Scan_Ini),Scan_Start
        move.b  -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
        lsl.w   #8,Scan_End
        move.b  -MIN_MATCH(Scan_Ini,Best_Len.w),Scan_End
.endif

        bra.b   do_scan

long_loop:

.ifdef  UNALIGNED_OK
        move.w  -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
.else
        move.b  -MIN_MATCH-1(Scan_Ini,Best_Len.w),Scan_End
        lsl.w   #8,Scan_End
        move.b  -MIN_MATCH(Scan_Ini,Best_Len.w),Scan_End
.endif

short_loop:
        lsl.w   #1,Cur_Match
        move.w  0(Prev_Address,Cur_Match.l),Cur_Match
        cmp.w   Limit,Cur_Match
        dbls    Chain_Length,do_scan
        bra.b   return

do_scan:
        move.l  Match_Ini,Match
        add.l   Cur_Match,Match

.ifdef  UNALIGNED_OK
        cmp.w   -MIN_MATCH-1(Match,Best_Len.w),Scan_End
        bne.b   short_loop
        cmp.w   -MIN_MATCH(Match),Scan_Start
        bne.b   short_loop
.else
        move.b  -MIN_MATCH-1(Match,Best_Len.w),Scan_Test
        lsl.w   #8,Scan_Test
        move.b  -MIN_MATCH(Match,Best_Len.w),Scan_Test
        cmp.w   Scan_Test,Scan_End
        bne.b   short_loop
        move.b  -MIN_MATCH(Match),Scan_Test
        lsl.w   #8,Scan_Test
        move.b  -MIN_MATCH+1(Match),Scan_Test
        cmp.w   Scan_Test,Scan_Start
        bne.b   short_loop
.endif

        move.w  #(MAX_MATCH-MIN_MATCH),Loop_Counter
        move.l  Scan_Ini,Scan
scan_loop:
        cmpm.b  (Match)+,(Scan)+
        dbne    Loop_Counter,scan_loop

        sub.l   Scan_Ini,Scan
        addq.l  #(MIN_MATCH-1),Scan
        cmp.l   Best_Len,Scan
        bls.b   short_loop
        move.l  Scan,Best_Len
        move.l  Cur_Match,_match_start
        cmp.l   _nice_match,Best_Len
        bcs.b   long_loop
return:
        move.l  Best_Len,d0
.ifdef  UNALIGNED_OK
        movem.l (sp)+,d2-d6/a2-a4
.else
        movem.l (sp)+,d2-d7/a2-a4
.endif
        rts

        end
