aboutsummaryrefslogtreecommitdiff
path: root/tools/apultra/asm/68000/unaplib_68000.S
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2021-01-09 09:01:05 +0000
committerJuan J. Martinez <jjm@usebox.net>2021-01-09 09:01:05 +0000
commit9bcf1e97960c0da7322a868efdbc07e2650716fe (patch)
treede6d32ad5b0e567991bd3eb262902c15a77074d9 /tools/apultra/asm/68000/unaplib_68000.S
parent3b31adf01305e522f7e28c1435fb47418ce43267 (diff)
downloadubox-msx-lib-9bcf1e97960c0da7322a868efdbc07e2650716fe.tar.gz
ubox-msx-lib-9bcf1e97960c0da7322a868efdbc07e2650716fe.zip
Extra libs: ap.lib
aPLib support with apultra.
Diffstat (limited to 'tools/apultra/asm/68000/unaplib_68000.S')
-rw-r--r--tools/apultra/asm/68000/unaplib_68000.S117
1 files changed, 117 insertions, 0 deletions
diff --git a/tools/apultra/asm/68000/unaplib_68000.S b/tools/apultra/asm/68000/unaplib_68000.S
new file mode 100644
index 0000000..a60ae32
--- /dev/null
+++ b/tools/apultra/asm/68000/unaplib_68000.S
@@ -0,0 +1,117 @@
+; unaplib_68000.s - aPLib decompressor for 68000 - 154 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
+ 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