aboutsummaryrefslogtreecommitdiff
path: root/tools/apultra/asm/68000/unaplib_68000.S
blob: 4ecf6ac257cb4b392cf6a9e4461da3243e4f1b81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
;  unaplib_68000.s - aPLib decompressor for 68000 - 156 bytes
;
;  in:  a0 = start of compressed data
;       a1 = start of decompression buffer
;  out: d0 = decompressed size
;
;  Copyright (C) 2020 Emmanuel Marty
;  With parts of the code inspired by Franck "hitchhikr" Charlet
;
;  This software is provided 'as-is', without any express or implied
;  warranty.  In no event will the authors be held liable for any damages
;  arising from the use of this software.
;
;  Permission is granted to anyone to use this software for any purpose,
;  including commercial applications, and to alter it and redistribute it
;  freely, subject to the following restrictions:
;
;  1. The origin of this software must not be misrepresented; you must not
;     claim that you wrote the original software. If you use this software
;     in a product, an acknowledgment in the product documentation would be
;     appreciated but is not required.
;  2. Altered source versions must be plainly marked as such, and must not be
;     misrepresented as being the original software.
;  3. This notice may not be removed or altered from any source distribution.

apl_decompress:
               movem.l a2-a6/d2-d3,-(sp)

               moveq #-128,d1       ; initialize empty bit queue
                                    ; plus bit to roll into carry
               lea 32000.w,a2       ; load 32000 offset constant
               lea 1280.w,a3        ; load 1280 offset constant
               lea 128.w,a4         ; load 128 offset constant
               move.l a1,a5         ; save destination pointer

.literal:      move.b (a0)+,(a1)+   ; copy literal byte
.after_lit:    moveq #3,d2          ; set LWM flag

.next_token:   bsr.s .get_bit       ; read 'literal or match' bit
               bcc.s .literal       ; if 0: literal

               bsr.s .get_bit       ; read '8+n bits or other type' bit
               bcs.s .other_match   ; if 11x: other type of match

               bsr.s .get_gamma2    ; 10: read gamma2-coded high offset bits
               sub.l d2,d0          ; high offset bits == 2 when LWM == 3 ?
               bcc.s .no_repmatch   ; if not, not a rep-match

               bsr.s .get_gamma2    ; read repmatch length
               bra.s .got_len       ; go copy large match

.no_repmatch:  lsl.l #8,d0          ; shift high offset bits into place
               move.b (a0)+,d0      ; read low offset byte
               move.l d0,d3         ; copy offset into d3

               bsr.s .get_gamma2    ; read match length
               cmp.l a2,d3          ; offset >= 32000 ?
               bge.s .inc_by_2      ; if so, increase match len by 2
               cmp.l a3,d3          ; offset >= 1280 ?
               bge.s .inc_by_1      ; if so, increase match len by 1
               cmp.l a4,d3          ; offset < 128 ?
               bge.s .got_len       ; if so, increase match len by 2
.inc_by_2:     addq.l #1,d0         ; increase match len by 1
.inc_by_1:     addq.l #1,d0         ; increase match len by 1

.got_len:      move.l a1,a6         ; calculate backreference address
               sub.l d3,a6          ; (dest - match offset)
               subq.l #1,d0         ; dbf will loop until d0 is -1, not 0
.copy_match:   move.b (a6)+,(a1)+   ; copy matched byte
               dbf d0,.copy_match   ; loop for all matched bytes
               moveq #2,d2          ; clear LWM flag
               bra.s .next_token    ; go decode next token

.other_match:  bsr.s .get_bit       ; read '7+1 match or short literal' bit
               bcs.s .short_match   ; if 111: 4 bit offset for 1-byte copy

               moveq #1,d0          ; 110: prepare match length
               moveq #0,d3          ; clear high bits of offset
               move.b (a0)+,d3      ; read low bits of offset + length bit
               lsr.b #1,d3          ; shift offset into place, len into carry
               beq.s .done          ; check for EOD
               addx.b d0,d0         ; len = (1 << 1) + carry bit, ie. 2 or 3
               bra.s .got_len       ; go copy match

.short_match:  moveq #0,d0          ; clear short offset before reading 4 bits
               bsr.s .get_dibits    ; read a data bit into d0, one into carry
               addx.b d0,d0         ; shift second bit into d0
               bsr.s .get_dibits    ; read a data bit into d0, one into carry
               addx.b d0,d0         ; shift second bit into d0
               tst.b d0             ; check offset value
               beq.s .write_zero    ; if offset is zero, write a 0

               move.l a1,a6         ; calculate backreference address
               sub.l d0,a6          ; (dest - short offset)
               move.b (a6),d0       ; read matched byte
.write_zero:   move.b d0,(a1)+      ; write matched byte or 0
               bra.s .after_lit     ; set LWM flag and go decode next token

.done:         move.l a1,d0         ; pointer to last decompressed byte + 1
               sub.l a6,d0          ; minus start of decompression buffer = size
               movem.l (sp)+,a2-a6/d2-d3
               rts

.get_gamma2:   moveq #1,d0          ; init to 1 so it gets shifted to 2 below
.gamma2_loop:  bsr.s .get_dibits    ; read data bit, shift into d0
                                    ; and read continuation bit
               bcs.s .gamma2_loop   ; loop until a 0 continuation bit is read
               rts

.get_dibits:   bsr.s .get_bit       ; read bit
               addx.l d0,d0         ; shift into d0
                                    ; fall through
.get_bit:      add.b d1,d1          ; shift bit queue, high bit into carry
               bne.s .got_bit       ; queue not empty, bits remain
               move.b (a0)+,d1      ; read 8 new bits
               addx.b d1,d1         ; shift bit queue, high bit into carry
                                    ; and shift 1 from carry into bit queue
.got_bit:      rts