aboutsummaryrefslogtreecommitdiff
path: root/lib/ucl.s
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2021-05-03 08:21:10 +0100
committerJuan J. Martinez <jjm@usebox.net>2021-05-03 10:00:00 +0100
commitc3b0fa04a663fe233765b83d3be41a42aa08c25d (patch)
tree0befda349001ef6ce306b39378f9c70ad917363e /lib/ucl.s
downloadreturn-of-traxtor-cpc-main.tar.gz
return-of-traxtor-cpc-main.zip
Initial import for public releaseHEADmain
Diffstat (limited to 'lib/ucl.s')
-rw-r--r--lib/ucl.s360
1 files changed, 360 insertions, 0 deletions
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
+; <adam@foxbox.org> <adam@gimp.org> - 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:
+; <http://www.foxbox.org/adam/code/uclz80/>
+;
+;
+; 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:
+