123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- ;===========================================================================
- ; 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
- ;===========================================================================
- ; This is a 68000 assembly language version of the Zip function
- ; longest_match(). It is written for any 680x0 based computer, but at this
- ; time the feature for runtime testing of CPU type is only supported for the
- ; Amiga. Hopefully a similar test for the Macintosh is possible, and for any
- ; other system that supports both 68000 and 68020+ CPUs. This is written by
- ; Paul Kienitz, partially derived from a simpler version by Carsten Steger,
- ; derived in turn from a 386 assembly function by Jean-loup Gailly and Kai Uwe
- ; Rommel... but also based directly on the C original.
- ;
- ; The main difference of this from other longest_match() implementations is
- ; that it includes both byte based and word based versions of the function,
- ; and various symbols can be defined to select whether to use one routine or
- ; the other, or to do a platform-specific test at runtime. The symbols that
- ; can be used to select behavior are as follows:
- ;
- ; CPU020 if defined, use 68020 instructions always
- ; CPUTEST if defined, check at runtime for CPU type. Another symbol
- ; specifying the platform-specific test must be used with this.
- ; If neither of these is defined, use 68000 instructions only.
- ; AMIGA use Amiga-specific test for 68020, if CPUTEST defined. Also
- ; tells it to let a0/a1/d1 be clobbered by functions.
- ; ATSIGN define entry symbols in @foo form as well as _foo, with
- ; @longest_match taking its parm in d0 instead of on the stack.
- ; WSIZE if defined, determines the sliding window size for deflate;
- ; the default is 32K. If you have reduced WSIZE for the C code,
- ; make sure that this module is assembled with an equivalent
- ; "-dWSIZE=<whatever>" (or "-e...") switch.
- ;
- ; NOTE: no provision is made for 16 bit ints. All external int variables are
- ; treated as 32 bit values. This also assumes that longest_match's result is
- ; returned in D0.
- IFND CPU020
- IFND CPUTEST
- CPU000 equ 1
- ENDC
- ENDC
- ; global variables:
- xref _max_chain_length ; unsigned int
- xref _prev_length ; unsigned int
- xref _match_start ; unsigned int
- xref _strstart ; unsigned int
- xref _good_match ; signed int
- xref _nice_match ; signed int
- xref _window ; array of unsigned char
- xref _prev ; array of unsigned short
- ; our entry points:
- xdef _match_init ; void match_init(void);
- xdef _longest_match ; int longest_match(unsigned cur_match);
- IFD ATSIGN
- xdef @match_init ; for SAS assembler
- xdef @longest_match ; ditto
- ENDC
- ; flag variable for remembering CPU type:
- IFD CPUTEST
- section cpuflag,data
- is020: ds.w 1
- ENDC
- section match,code
- _match_init:
- IFD ATSIGN
- @match_init:
- ENDC
- IFD CPUTEST ; now check for platform type
- IFD AMIGA ; Amiga specific test for '020 CPU:
- xref _SysBase
- NOLIST
- INCLUDE 'exec/execbase.i'
- LIST
- clr.w is020 ; default value is 68000
- move.l _SysBase,a0
- btst #AFB_68020,AttnFlags+1(a0)
- beq.s cheap
- move.w #1,is020
- cheap:
- ELSE ; !AMIGA
- !! Write an '020-detector for your system here!
- ENDC ; AMIGA
- ENDC ; CPUTEST
- rts ; match_init consists only of rts if CPUTEST unset
- IFD AMIGA
- SAVEREGS reg d3-d7/a2/a3/a5 ; don't protect d0/d1/a0/a1
- ELSE
- SAVEREGS reg d1/d3-d7/a0-a3/a5 ; protect all but d0 return val
- ENDC
- Cur_Match equr d0 ; Must be in d0!
- Best_Len equr d1
- Scan_Start equr d3
- Scan_End equr d4
- Limit equr d5
- Chain_Length equr d6
- Scan_Test equr d7
- Scan equr a0
- Match equr a1
- Prev_Address equr a2
- Scan_Ini equr a3
- Match_Ini equr a5
- MAX_MATCH equ 258
- MIN_MATCH equ 3
- IFND WSIZE
- WSIZE equ 32768
- ENDC
- MAX_DIST equ WSIZE-MAX_MATCH-MIN_MATCH-1
- _longest_match:
- move.l 4(sp),Cur_Match ; stack arg to register
- IFD ATSIGN
- @longest_match:
- ENDC
- movem.l SAVEREGS,-(sp)
- ; setup steps common to byte and word versions:
- move.l _max_chain_length,Chain_Length
- move.l _prev_length,Best_Len
- lea _prev,Prev_Address
- lea _window,Match_Ini
- move.l _strstart,Limit
- move.l Match_Ini,Scan_Ini
- addq #MIN_MATCH,Match_Ini
- add.l Limit,Scan_Ini
- subi.w #MAX_DIST,Limit
- bhi.s limit_ok
- moveq #0,Limit
- limit_ok:
- cmp.l _good_match,Best_Len
- bcs.s length_ok
- lsr.l #2,Chain_Length
- length_ok:
- subq.l #1,Chain_Length
- IFD CPUTEST
- tst.w is020 ; can we use '020 stuff today?
- bne WORD_match
- ENDC
- IFND CPU020
- ; for 68000 or 68010, use byte operations:
- moveq #0,Scan_Start ; clear 2nd and 4th bytes, use 1st & 3rd
- moveq #0,Scan_End
- moveq #0,Scan_Test
- move.b (Scan_Ini),Scan_Start
- swap Scan_Start
- move.b 1(Scan_Ini),Scan_Start
- move.b -1(Scan_Ini,Best_Len),Scan_End
- swap Scan_End
- move.b 0(Scan_Ini,Best_Len),Scan_End
- bra.s bdo_scan
- blong_loop:
- move.b -1(Scan_Ini,Best_Len),Scan_End
- swap Scan_End
- move.b 0(Scan_Ini,Best_Len),Scan_End
- bshort_loop:
- add.w Cur_Match,Cur_Match
- move.w 0(Prev_Address,Cur_Match.l),Cur_Match
- cmp.l Limit,Cur_Match
- dbls Chain_Length,bdo_scan
- bra return
- bdo_scan:
- move.l Match_Ini,Match
- add.l Cur_Match,Match
- move.b -MIN_MATCH-1(Match,Best_Len),Scan_Test
- swap Scan_Test
- move.b -MIN_MATCH(Match,Best_Len),Scan_Test
- cmp.l Scan_Test,Scan_End
- bne.s bshort_loop
- move.b -MIN_MATCH(Match),Scan_Test
- swap Scan_Test
- move.b -MIN_MATCH+1(Match),Scan_Test
- cmp.l Scan_Test,Scan_Start
- bne.s bshort_loop
- move.w #(MAX_MATCH-MIN_MATCH),Scan_Test
- lea MIN_MATCH(Scan_Ini),Scan
- bscan_loop:
- cmpm.b (Match)+,(Scan)+
- dbne Scan_Test,bscan_loop
- subq #1,Scan
- sub.l Scan_Ini,Scan
- cmp.l Best_Len,Scan
- bls.s bshort_loop
- move.l Scan,Best_Len
- move.l Cur_Match,_match_start
- cmp.l _nice_match,Best_Len
- bcs.s blong_loop
- IFD CPUTEST
- bra return
- ENDC
- ENDC ; !CPU020
- IFND CPU000
- ; for 68020 or higher, use word operations even on odd addresses:
- WORD_match:
- move.w (Scan_Ini),Scan_Start
- move.w -1(Scan_Ini,Best_Len),Scan_End
- bra.s wdo_scan
- wlong_loop:
- move.w -1(Scan_Ini,Best_Len),Scan_End
- wshort_loop:
- add.w Cur_Match,Cur_Match
- move.w (Prev_Address,Cur_Match.l),Cur_Match
- cmp.l Limit,Cur_Match
- dbls Chain_Length,wdo_scan
- bra.s return
- wdo_scan:
- move.l Match_Ini,Match
- add.l Cur_Match,Match
- cmp.w -MIN_MATCH-1(Match,Best_Len),Scan_End
- bne.s wshort_loop
- cmp.w -MIN_MATCH(Match),Scan_Start
- bne.s wshort_loop
- moveq #((MAX_MATCH-MIN_MATCH)/2),Scan_Test ; value = 127
- lea MIN_MATCH(Scan_Ini),Scan
- wscan_loop:
- cmpm.w (Match)+,(Scan)+
- dbne Scan_Test,wscan_loop
- subq #2,Scan
- move.b -MIN_MATCH+1(Match),Scan_Test
- cmp.b (Scan),Scan_Test
- bne steven
- addq #1,Scan
- steven:
- sub.l Scan_Ini,Scan
- cmp.l Best_Len,Scan
- bls.s wshort_loop
- move.l Scan,Best_Len
- move.l Cur_Match,_match_start
- cmp.l _nice_match,Best_Len
- bcs.s wlong_loop
- ENDC ; !CPU000
- return:
- move.l Best_Len,d0 ; function return value
- movem.l (sp)+,SAVEREGS
- rts
- end
|