From c3b0fa04a663fe233765b83d3be41a42aa08c25d Mon Sep 17 00:00:00 2001 From: "Juan J. Martinez" Date: Mon, 3 May 2021 08:21:10 +0100 Subject: Initial import for public release --- lib/ucl.s | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 lib/ucl.s (limited to 'lib/ucl.s') diff --git a/lib/ucl.s b/lib/ucl.s new file mode 100644 index 0000000..68b1b48 --- /dev/null +++ b/lib/ucl.s @@ -0,0 +1,360 @@ +; UCLZ80: -*- asm -*- +; 2bunpack: unpack data compressed with M.F.X.J. Oberhumer''s +; UCL/2B algorithm. Decompressor for Z80 (c) 2000 Adam D. Moss +; - All rights reserved +; +; Version 0.99-beta2: 2000-10-25 +; ** COMMENTS, FIXES ETC ARE WELCOMED ** + If you use this, I''d love to hear. +; +; Permission is hereby granted, free of #0xcarge, to any person obtaining a +; copy of this software and associated documentation files (the "Software"), +; to deal in the Software without restriction, including without limitation +; the rights to use, copy, modify, merge, publish, distribute, sublicense, +; and/or sell copies of the Software, and to permit persons to whom the +; Software is furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included +; in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +; THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +; IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +; +; (In laymans'' terms this code is essentially public domain.) +; +; Latest versions and docs, plus pointers to associated utilities and +; M.F.X.J. Oberhumer''s *compressor* for UCL/2B streams are always +; available from the UCLZ80 home page: +; +; +; +; UPDATE: http://icculus.org/~aspirin/uclz80/ +; +; RELEASE HISTORY: +; v0.99-beta2: 2000-10-25: Rearrangement, comments, public release +; v0.99-beta1: 2000-07-30: Optimizations, comments and fixes +; v0.50 : 2000-07-22: Initial version + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Assembly syntax compatible with ZMAC and ASL cross-assemblers. +; Undocumented Z80 instructions have been inserted in byte form. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; CALL: +; L2bunpack +; INPUTS: +; bc = PACKED DATA SOURCE ADDRESS +; de = UNPACKED DATA DESTINATION ADDRESS +; STACK USAGE: +; 2 bytes excluding call overhead +; REGISTER USAGE: +; leaves IY, IXH and all alternative registers intact +; SIZE: +; 245 bytes +; +; NOTES: +; ''In-place'' unpacking of overlapping src/dest is also supported; +; use external utility to find the maximum overlap for a given +; block of data ((UNPACKED_SIZE - n) where n is usually around 7-10 +; bytes). +; +; No #0xcecking of data integrity is performed by this unpacker. +; +; The length of the unpacked data is implicit in the packed stream; +; you should know in advance the length to whi#0xc a given compressed +; stream unpacks (ie. from out-of-band metadata), to provide enough +; space in the destination memory area. + +.globl _ucl_uncompress + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; loops taken out of line +L2bloop1_0: ; DON''T CALL HERE, these functions are just here for JR-locality + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr C, L2bloop1_work ; we carried, do the work -ADM:GetStats + jp L2bloop1_end ; otherwise drop out + +L2bloop2a_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr NC, L2bloop2a_skip_set + jp L2bloop2a_set + +L2bloop2b_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr C, L2bloop2b_end ; if !bit then end loop + jp L2bloop2a ; if bit then restart big loop + + +L2bjmp3_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jp L2bjmp3_r + +L2b_term: ; springboard placed here to be within JR r#0xeac + jp L2b_end + +;;; +;;; my EP +_ucl_uncompress:: + ld ix, #2 + add ix, sp + ld c, (ix) + ld b, 1(ix) + ld e, 2(ix) + ld d, 3(ix) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CALL HERE: +L2bunpack: + ; init variables + .db #0x0DD,#0x2E,#0x00 ; LD IXL, 0; bit-bucket lives in IXL + ld hl, #0x1 + ld (prev_doffset), hl + +L2bmain: +L2bloop1: ;;;; while nextbit()==1 *dest++ = *src++; + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop1_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop1_end ; nextbit()==0, end loop ; STAT +L2bloop1_work: + ; nextbit() == 1, so *dest++ = *src++; + ld a, (bc) + ld (de), a + inc de + inc bc + jp L2bloop1 +L2bloop1_end: + + + ld hl, #0x1 ;; doffset = 1 + ; doffset lives in HL until further notice! + +L2bloop2a: + add hl, hl + jr C, L2b_term ; terminator found. ; STAT + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop2a_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop2a_skip_set ; STAT +L2bloop2a_set: + inc hl ;; doffset++ +L2bloop2a_skip_set: + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop2b_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop2a ; if nextbit() loop again ; STAT +L2bloop2b_end: + + + ld a, l + sub #0x2 + or h + jr NZ, L2bjmp3 ; doffset != 2 then jump ; STAT + ld hl, (prev_doffset) ;; doffset = prev_doffset + jp L2bjmp3_end +L2bjmp3: + dec l + dec l + dec l ; hl is doffset again + ld h, l ; *=256, now put something in l + ld a, (bc) + inc bc ;; ilen++ + ld l, a + inc hl ;; doffset++ + ld (prev_doffset),hl +L2bjmp3_end: + + ld (doffset),hl + ; doffset committed to memory. + + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bjmp3_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A +L2bjmp3_r: + ; bit now in C flag + ld hl, #0x0 + jp NC, L2bjmp3_skipset ; STAT + ld l, #0x2 ;; movlen = 1, movlen *= 2 +L2bjmp3_skipset: + + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bjmp4_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bjmp4_zero ; STAT +L2bjmp4_nonzero: + ; movlen in HL (well, only low 2 L bits have stuff) + inc hl +L2bjmp4_zero: + + + xor a + or l ; movlen == 0? + jr NZ, L2bjmp8_movlen_nonzero ; STAT + + ; so movlen == 0 + inc l ;; movlen = 1 + + +L2bloop6: + add hl, hl ;; movlen *= 2 + + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop6_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop6_zero ; STAT +L2bloop6_nonzero: + inc hl;(hl) +L2bloop6_zero: + ;;;; CF = nextbit() + .db #0x0DD,#0x7D ; LD A, IXL + add a, a + jr Z, L2bloop7_0 ; ran out of bits: load new byte + .db #0x0DD,#0x6F ; LD IXL,A + ; bit now in C flag + jr NC, L2bloop6 ; go around loop again ; STAT +L2bloop7_nonzero: + ; !!nextbit(), loop broken + inc hl + inc hl + + +L2bjmp8_movlen_nonzero: +L2bjmp8a_0d00_compare: + + push bc + + ld bc, (doffset) ;20 + xor a, a ;4 + sub a, c ;4 + ld a, #0x0D ;7 + sbc a, b ;4 == 42 + + jp NC, L2bjmp9_noadd ; STAT + + ; so (doffset > #0x0d00) + inc hl ;; movlen++ + +L2bjmp9_noadd: + ; movlen is in HL + + ; reshuffle registers to be LDIR-friendly + ;want dest (de) in de + ;want src (de-doffset) in hl + ;want movlen (hl) in bc + + ld b, h ;4 + ld c, l ;4 + ld hl, (doffset) ;20 + + ld a, e ;4 + sub l ;4 + ld l, a ;4 + ld a, d ;4 + sbc a, h ;4 + ld h, a ;4 == 52 + ; done shuffling. + + ldi + inc bc + ldir + + pop bc + + jp L2bmain + + +L2b_end: +; ld a, 4 ;DEBUG +; out (254), a ;DEBUG + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; out-of-line jumps +L2bloop7_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr NC, L2bloop6 + jp L2bloop7_nonzero + + +L2bloop6_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr NC, L2bloop6_zero + jp L2bloop6_nonzero + + +L2bjmp4_0: + ;;;; bb = *src, src++ + ld a, (bc) ; get *src + inc bc ; src++ + scf + rla ; ADM: could use undoc''d SLL + .db #0x0DD,#0x6F ; LD IXL,A + + jr NC, L2bjmp4_zero + jp L2bjmp4_nonzero + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +prev_doffset: .dw #0x0000 +doffset: .dw #0x0000 + +L2b_unpack_ENDSYMBOL: + -- cgit v1.2.3