📄 deflate.a
字号:
move.b -MIN_MATCH(Match,Best_Len.w),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-3),Scan_Test lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loopbscan_loop: cmp.b (Match)+,(Scan)+ dbne Scan_Test,bscan_loop subq #1,Scan sub.l Scan_Ini,Scan ; assert difference is 16 bits cmp.w Best_Len,Scan bls.s bshort_loop MOVINT Scan,Best_Len move.w Cur_Match,match_start cmp.w nice_match,Best_Len blo.s blong_loop IFD CPUTEST bra return ENDC ENDC ; !CPU020 IFND CPU000 MACHINE MC68020; 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.w),Scan_End bra.s wdo_scanwlong_loop: move.w -1(Scan_Ini,Best_Len.w),Scan_Endwshort_loop: and.w #WMASK,Cur_Match move.w (Prev_Address,Cur_Match.w*2),Cur_Match ; '020 addressing mode cmp.w Limit,Cur_Match dbls Chain_Length,wdo_scan bra.s returnwdo_scan: move.l Match_Ini,Match add.l Cur_Match,Match cmp.w -MIN_MATCH-1(Match,Best_Len.w),Scan_End bne.s wshort_loop cmp.w -MIN_MATCH(Match),Scan_Start bne.s wshort_loop IFD QUADLONG; By some measurements, this version of the code is a little tiny bit faster.; But on some files it's slower. It probably pays off only when there are; long match strings, and costs in the most common case of three-byte matches. moveq #((MAX_MATCH-MIN_MATCH)/16),Scan_Test ; value = 15 lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loopwscan_loop: cmp.l (Match)+,(Scan)+ ; test four bytes at a time bne.s odd cmp.l (Match)+,(Scan)+ bne.s odd cmp.l (Match)+,(Scan)+ bne.s odd cmp.l (Match)+,(Scan)+ dbne Scan_Test,wscan_loop ; '020 can cache a bigger loopodd: subq #4,Scan subq #4,Match cmp.b (Match)+,(Scan)+ ; find good bytes in bad longword bne.s even cmp.b (Match)+,(Scan)+ bne.s even cmp.b (Match)+,(Scan)+ beq.s steveneven: subq #1,Scan ELSE ; !QUADLONG moveq #((MAX_MATCH-MIN_MATCH)/2),Scan_Test ; value = 127 lea MIN_MATCH(Scan_Ini),Scan ; offset optimizes inner loopwscan_loop: cmp.w (Match)+,(Scan)+ dbne Scan_Test,wscan_loop subq #2,Scan move.b -2(Match),Scan_Test cmp.b (Scan),Scan_Test bne.s steven addq #1,Scan ENDC ; ?QUADLONGsteven: sub.l Scan_Ini,Scan ; assert: difference is 16 bits cmp.w Best_Len,Scan bls.s wshort_loop MOVINT Scan,Best_Len move.w Cur_Match,match_start cmp.w nice_match,Best_Len blo.s wlong_loop MACHINE MC68000 ENDC ; !CPU000return: MOVINT Best_Len,d0 ; return value (upper half should be clear) movem.l (sp)+,SAVEREGS rts; =============================================================================; This is the deflate() function itself, our main entry point. It calls; longest_match, above, and some outside functions. It is a hot spot, but not; as hot as longest_match. It uses no special '020 code.; ================== Several macros used in deflate() and later functions:; Arg 1 is D-reg that new ins_h value is to be left in,; arg 2 is the byte value to be hashed into it, which must not be the same regUP_HASH MACRO move.w ins_h,\1 asl.w #H_SHIFT,\1 eor.b \2,\1 and.w #HASH_MASK,\1 ; ((ins_h << H_SHIFT) ^ c) & HASH_MASK move.w \1,ins_h ; ins_h = that ENDM; Arg 1 is scratch A, arg 2 is scratch DIN_STR MACRO move.l Strst,\2 addq.w #MIN_MATCH-1,\2 move.b (Window,\2.l),\2 ; window[strstart + MIN_MATCH - 1] UP_HASH Head,\2 add.l Head,Head ; assert upper word is zero before add BASEPTR _head,\1 add.l Head,\1 move.w (\1),Head ; hash_head = head[ins_h] move.w Strst,(\1) ; head[ins_h] = strstart move.l Strst,\2 IFNE WSIZE-32768 and.w #WMASK,\2 ENDC add.w \2,\2 ; masks implicitly when WSIZE == 32768 move.w Head,(Prev,\2.l) ; prev[str_start & WMASK] = hash_head ENDM; Arg 1 is bool (int) EOF flag, flush_block result is in d0, trashes d1/a0/a1FLUSH_B MACRO IFC '\1','#0' CLRINT -(sp) ELSE MOVINT \1,-(sp) ENDC move.l _block_start,d0 blt.s nenu\@ move.l Window,a0 add.l d0,a0 bra.s nun\@nenu\@: sub.l a0,a0 ; if block_start < 0, push NULLnun\@: sub.l Strst,d0 neg.l d0 move.l d0,-(sp) move.l a0,-(sp) jsr _flush_block lea 8+INTSIZE(sp),sp ENDM; This expands to nothing unless DEBUG is defined.; Arg 1 is a byte to be trace-outputted -- if it is d0 it must be a valid intTRACE_C MACRO IFD DEBUG cmp.w #1,_verbose+INTSIZE-2 ; test lower word only ble.s qui\@ IFNC '\1','d0' moveq #0,d0 move.b \1,d0 ENDC move.l _stderr,-(sp) MOVINT d0,-(sp) jsr _fputc addq #4+INTSIZE,spqui\@: ENDC ; DEBUG ENDM; ================== Here are the register vars we use, and deflate() itself:Window equr a2 ; cached address of window[]Prev equr a3 ; cached address of prev[]Strst equr d7 ; strstart cached as a longwordLook equr d6 ; lookahead cached as shortHead equr d5 ; local variable hash_head, shortPrevL equr d4 ; prev_length cached as shortMatchL equr d3 ; local variable match_length, unsigned shortAvail equr d2 ; local variable available_match, boolPrevM equr a5 ; local variable prev_match, int in an A-reg IFD AMIGADEFREGS reg d2-d7/a2/a3/a5 ELSEDEFREGS reg d0-d7/a0/a2/a3/a5 ; play it safe, preserve all regs ENDC_deflate: ; first, setup steps common to deflate and deflate_fast: movem.l DEFREGS,-(sp) IFD INT16 moveq #0,Strst ; make sure strstart is valid as a long ENDC moveq #0,Head ; ditto for hash_head MOVINT _strstart,Strst move.w lookahead,Look move.w prev_length,PrevL BASEPTR _window,Window BASEPTR _prev,Prev MOVINT _level,d0 cmp.w #3,d0 ble deflate_fast moveq #MIN_MATCH-1,MatchL moveq #0,Availlook_loop: tst.w Look beq last_tally IN_STR a0,d0 move.w MatchL,PrevL move.w match_start,PrevM move.w #MIN_MATCH-1,MatchL tst.w Head beq.s no_new_match cmp.w max_lazy_match,PrevL bhs.s no_new_match move.w Strst,d0 sub.w Head,d0 cmp.w #MAX_DIST,d0 bhi.s no_new_match move.w PrevL,prev_length ; longest_match reads these variables MOVINT Strst,_strstart MOVINT Head,d0 ; parm for longest_match bsr longest_match ; sets match_start cmp.w Look,d0 ; does length exceed valid data? bls.s stml move.w Look,d0stml: move.w d0,MatchL ; valid length of match cmp.w #MIN_MATCH,MatchL ; is the match only three bytes? bne.s no_new_match move.w match_start,d0 sub.w Strst,d0 cmp.w #-TOO_FAR,d0 bge.s no_new_match moveq #MIN_MATCH-1,MatchL ; mark the current match as no goodno_new_match: cmp.w #MIN_MATCH,PrevL blo literal cmp.w MatchL,PrevL blo literal ; CHECK_MATCH Strst-1,PrevM,PrevL MOVINT Strst,_strstart ; ct_tally reads this variable move.l PrevL,d0 subq.w #MIN_MATCH,d0 MOVINT d0,-(sp) move.l Strst,d0 sub.w PrevM,d0 subq.w #1,d0 MOVINT d0,-(sp) jsr _ct_tally ; sets d0 true if we have to flush addq #2*INTSIZE,sp subq.w #3,PrevL ; convert for dbra (prev_length - 2) sub.w PrevL,Look subq.w #2,Lookinsertmatch: addq.w #1,Strst IN_STR a0,d1 ; don't clobber d0 dbra PrevL,insertmatch moveq #0,Avail moveq #0,PrevL ; not needed? moveq #MIN_MATCH-1,MatchL addq.w #1,Strst tst.w d0 beq refill FLUSH_B #0 move.l Strst,_block_start bra.s refillliteral: tst.w Avail bne.s yeslit moveq #1,Avail bra.s skipliteralyeslit: TRACE_C <-1(Window,Strst.l)> MOVINT Strst,_strstart ; ct_tally reads this variable moveq #0,d0 move.b -1(Window,Strst.l),d0 MOVINT d0,-(sp) CLRINT -(sp) jsr _ct_tally addq #2*INTSIZE,sp tst.w d0 beq.s skipliteral FLUSH_B #0 move.l Strst,_block_startskipliteral: addq.w #1,Strst subq.w #1,Lookrefill: cmp.w #MIN_LOOKAHEAD,Look bhs look_loop bsr fill_window bra look_looplast_tally: tst.w Avail beq last_flush MOVINT Strst,_strstart ; ct_tally reads this variable moveq #0,d0 move.b -1(Window,Strst.l),d0 MOVINT d0,-(sp) CLRINT -(sp) jsr _ct_tally addq #2*INTSIZE,splast_flush: FLUSH_B #1 bra deflate_exit; ================== This is another version used for low compression levels:deflate_fast: moveq #0,MatchL moveq #MIN_MATCH-1,PrevLflook_loop: tst.w Look beq flast_flush IN_STR a0,d0 tst.w Head beq.s fno_new_match move.w Strst,d0 sub.w Head,d0 cmp.w #MAX_DIST,d0 bhi.s fno_new_match move.w PrevL,prev_length ; longest_match reads these variables MOVINT Strst,_strstart MOVINT Head,d0 ; parm for longest_match bsr longest_match ; sets match_start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -