;
; Copyright (C) 1990-1996 Mark Adler, Richard B. Wales, Jean-loup Gailly,
; Onno van der Linden, Kai Uwe Rommel, Igor Mandrichenko, Sergio Monesi and
; Karl Davis.
; Permission is granted to any individual or institution to use, copy, or
; redistribute this software so long as all of the original files are included,
; that it is not sold for profit, and that this copyright notice is retained.
;
; match.s for ARM by Sergio Monesi.

r0 RN 0
r1 RN 1
r2 RN 2
r3 RN 3
r4 RN 4
r5 RN 5
r6 RN 6
r7 RN 7
r8 RN 8
r9 RN 9
sl RN 10
fp RN 11
ip RN 12
sp RN 13
lr RN 14
pc RN 15

MAX_DIST   EQU  32506
WMASK      EQU  32767
MAX_MATCH  EQU  258

                AREA    |C$$code|, CODE, READONLY


; r1 = chain_lenght
; r2 = scan
; r3 = match
; r4 = len (tmp)
; r5 = best_len
; r6 = limit
; r7 = strend
; r8 = scan_end1
; r9 = scan_end
; lr = window
; fp = prev

|__max_chain_length|
        IMPORT  max_chain_length
        DCD     max_chain_length
|__window|
        IMPORT  window
        DCD     window
|__prev|
        IMPORT  prev
        DCD     prev
|__prev_length|
        IMPORT  prev_length
        DCD     prev_length
|__strstart|
        IMPORT  strstart
        DCD     strstart
|__good_match|
        IMPORT  good_match
        DCD     good_match
|__nice_match|
        IMPORT  nice_match
        DCD     nice_match
|__match_start|
        IMPORT  match_start
        DCD     match_start

        DCB     "longest_match"
        DCB     &00,&00,&00
        DCD     &ff000010

        EXPORT  longest_match
longest_match
        STMFD   sp!, {r4-r9,fp,lr}

        LDR     fp, [pc, #|__prev|-.-8]

        LDR     r1, [pc, #|__max_chain_length|-.-8]
        LDR     r1, [r1]
        LDR     lr, [pc, #|__window|-.-8]

        LDR     ip, [pc, #|__strstart|-.-8]
        LDR     ip, [ip]
        ADD     r2, lr, ip
        LDR     r5, [pc, #|__prev_length|-.-8]
        LDR     r5, [r5]
        SUBS    ip, ip, #MAX_DIST-250       ; if r6 > MAX_DIST
        SUBCSS  r6, ip, #250                ; r6 = r6 - MAXDIST
        MOVLS   r6, #0                      ; else r6 = 0

        ADD     r7, r2, #MAX_MATCH-256
        ADD     r7, r7, #256                ; r7 = r2 + MAX_MATCH (=258);

        SUB     ip, r5, #1
        LDRB    r8, [r2, ip]
        LDRB    r9, [r2, r5]

        LDR     ip, [pc, #|__good_match|-.-8]
        LDR     ip, [ip]
        CMP     r5, ip
        MOVCS   r1, r1, LSR #2

cycle
        ADD     r3, lr, r0

        LDRB    ip, [r3, r5]
        CMP     ip, r9
        BNE     cycle_end

        SUB     ip, r5, #1
        LDRB    ip, [r3, ip]
        CMP     ip, r8
        BNE     cycle_end

        LDRB    ip, [r2]
        LDRB    r4, [r3]
        CMP     ip, r4
        BNE     cycle_end

        LDRB    ip, [r3, #1]
        LDRB    r4, [r2, #1]
        CMP     ip, r4
        BNE     cycle_end

        ADD     r2, r2, #2
        ADD     r3, r3, #2

inn_cycle
        LDRB    ip, [r2, #1]!
        LDRB    r4, [r3, #1]!
        CMP     ip, r4
        BNE     exit_inn_cycle

        LDRB    ip, [r2, #1]!
        LDRB    r4, [r3, #1]!
        CMP     ip, r4
        BNE     exit_inn_cycle

        LDRB    ip, [r2, #1]!
        LDRB    r4, [r3, #1]!
        CMP     ip, r4
        BNE     exit_inn_cycle

        LDRB    ip, [r2, #1]!
        LDRB    r4, [r3, #1]!
        CMP     ip, r4
        BNE     exit_inn_cycle

        LDRB    ip, [r2, #1]!
        LDRB    r4, [r3, #1]!
        CMP     ip, r4
        BNE     exit_inn_cycle

        LDRB    ip, [r2, #1]!
        LDRB    r4, [r3, #1]!
        CMP     ip, r4
        BNE     exit_inn_cycle

        LDRB    ip, [r2, #1]!
        LDRB    r4, [r3, #1]!
        CMP     ip, r4
        BNE     exit_inn_cycle

        LDRB    ip, [r2, #1]!
        LDRB    r4, [r3, #1]!
        CMP     ip, r4
        BNE     exit_inn_cycle

        CMP     r2, r7
        BCC     inn_cycle

exit_inn_cycle
        SUB     r4, r2, r7               ; len = MAX_MATCH - (int)(strend - scan);
        ADD     r4, r4, #MAX_MATCH-256
        ADD     r4, r4, #256

        SUB     r2, r2, r4               ; scan = strend - MAX_MATCH

        CMP     r4, r5                   ; if (len > best_len) {
        BLE     cycle_end

        LDR     ip, [pc, #|__match_start|-.-8]  ; match_start = cur_match;
        STR     r0, [ip]
        MOV     r5, r4                          ; best_len = len;

        LDR     ip, [pc, #|__nice_match|-.-8]   ; if (len >= nice_match)
        LDR     ip, [ip]
        CMP     r4, ip
        BGE     exit_match                      ;   break;

        SUB     ip, r5, #1                      ; scan_end1  = scan[best_len-1];
        LDRB    r8, [r2, ip]
        LDRB    r9, [r2, r5]                    ; scan_end   = scan[best_len];

cycle_end
        MOV     ip, r0, LSL #17          ; cur_match & WMASK
        MOV     ip, ip, LSR #17

        LDR     r0, [fp, ip, ASL #1]     ; cur_match = prev[cur_match & WMASK]
        MOV     r0, r0, ASL #16
        MOV     r0, r0, LSR #16

        CMP     r0, r6                  ; cur_match > limit
        BLS     exit_match
        SUBS    r1, r1, #1              ; --chain_length
        BNE     cycle                   ; chain_length != 0

exit_match
        MOV     r0, r5

        LDMFD   sp!, {r4-r9,fp,pc}^

        END
