diff options
author | Juan J. Martinez <jjm@usebox.net> | 2021-01-09 09:01:05 +0000 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2021-01-09 09:01:05 +0000 |
commit | 9bcf1e97960c0da7322a868efdbc07e2650716fe (patch) | |
tree | de6d32ad5b0e567991bd3eb262902c15a77074d9 /tools/apultra/asm/6502 | |
parent | 3b31adf01305e522f7e28c1435fb47418ce43267 (diff) | |
download | ubox-msx-lib-9bcf1e97960c0da7322a868efdbc07e2650716fe.tar.gz ubox-msx-lib-9bcf1e97960c0da7322a868efdbc07e2650716fe.zip |
Extra libs: ap.lib
aPLib support with apultra.
Diffstat (limited to 'tools/apultra/asm/6502')
-rw-r--r-- | tools/apultra/asm/6502/aplib_6502.asm | 257 | ||||
-rw-r--r-- | tools/apultra/asm/6502/aplib_6502_b.asm | 218 |
2 files changed, 475 insertions, 0 deletions
diff --git a/tools/apultra/asm/6502/aplib_6502.asm b/tools/apultra/asm/6502/aplib_6502.asm new file mode 100644 index 0000000..1bc11b4 --- /dev/null +++ b/tools/apultra/asm/6502/aplib_6502.asm @@ -0,0 +1,257 @@ +; *************************************************************************** +; *************************************************************************** +; +; aplib_6502.s +; +; NMOS 6502 decompressor for data stored in Jorgen Ibsen's aPLib format. +; +; Includes support for Emmanuel Marty's enhancements to the aPLib format. +; +; The code is 252 bytes long for standard format, 270 for enhanced format. +; +; This code is written for the ACME assembler. +; +; Copyright John Brandwood 2019. +; +; Distributed under the Boost Software License, Version 1.0. +; (See accompanying file LICENSE_1_0.txt or copy at +; http://www.boost.org/LICENSE_1_0.txt) +; +; *************************************************************************** +; *************************************************************************** + + + +; *************************************************************************** +; *************************************************************************** +; +; Decompression Macros +; + + ; + ; Macro to increment the source pointer to the next page. + ; + + !macro APL_INC_PAGE { + inc <apl_srcptr + 1 + } + + ; + ; Macro to read a byte from the compressed source data. + ; + + !macro APL_GET_SRC { + lda (apl_srcptr),y + inc <apl_srcptr + 0 + bne .skip + +APL_INC_PAGE +.skip: + } + + + +; *************************************************************************** +; *************************************************************************** +; +; Data usage is last 12 bytes of zero-page. +; + +apl_bitbuf = $F7 ; 1 byte. +apl_offset = $F8 ; 1 word. +apl_winptr = $FA ; 1 word. +apl_srcptr = $FC ; 1 word. +apl_dstptr = $FE ; 1 word. +apl_length = apl_winptr + + +; *************************************************************************** +; *************************************************************************** +; +; apl_decompress - Decompress data stored in Jorgen Ibsen's aPLib format. +; +; Args: apl_srcptr = ptr to compessed data +; Args: apl_dstptr = ptr to output buffer +; Uses: lots! +; +; As an optimization, the code to handle window offsets > 64768 bytes has +; been removed, since these don't occur with a 16-bit address range. +; +; As an optimization, the code to handle window offsets > 32000 bytes can +; be commented-out, since these don't occur in typical 8-bit computer usage. +; + +apl_decompress: ldy #0 ; Initialize source index. + + lda #$80 ; Initialize an empty + sta <apl_bitbuf ; bit-buffer. + + ; + ; 0 bbbbbbbb - One byte from compressed data, i.e. a "literal". + ; + +.literal: +APL_GET_SRC + +.write_byte: ldx #0 ; LWM=0. + + sta (apl_dstptr),y ; Write the byte directly to + inc <apl_dstptr + 0 ; the output. + bne .next_tag + inc <apl_dstptr + 1 + +.next_tag: asl <apl_bitbuf ; 0 bbbbbbbb + bne .skip0 + jsr .load_bit +.skip0: bcc .literal + +.skip1: asl <apl_bitbuf ; 1 0 <offset> <length> + bne .skip2 + jsr .load_bit +.skip2: bcc .copy_large + + asl <apl_bitbuf ; 1 1 0 dddddddn + bne .skip3 + jsr .load_bit +.skip3: bcc .copy_normal + + ; 1 1 1 dddd - Copy 1 byte within 15 bytes (or zero). + +.copy_short: lda #$10 +.nibble_loop: asl <apl_bitbuf + bne .skip4 + pha + jsr .load_bit + pla +.skip4: rol + bcc .nibble_loop + beq .write_byte ; Offset=0 means write zero. + + eor #$FF ; Read the byte directly from + tay ; the destination window. + iny + dec <apl_dstptr + 1 + lda (apl_dstptr),y + inc <apl_dstptr + 1 + ldy #0 + beq .write_byte + + ; + ; 1 1 0 dddddddn - Copy 2 or 3 within 128 bytes. + ; + +.copy_normal: +APL_GET_SRC ; 1 1 0 dddddddn + lsr + beq .finished ; Offset 0 == EOF. + + sta <apl_offset + 0 ; Preserve offset. + sty <apl_offset + 1 + tya ; Y == 0. + tax ; Bits 8..15 of length. + adc #2 ; Bits 0...7 of length. + bne .do_match ; NZ from previous ADC. + + ; + ; Subroutines for byte & bit handling. + ; + +.get_gamma: lda #1 ; Get a gamma-coded value. +.gamma_loop: asl <apl_bitbuf + bne .skip5 + pha + jsr .load_bit + pla +.skip5: rol + rol <apl_length + 1 + asl <apl_bitbuf + bne .skip6 + pha + jsr .load_bit + pla +.skip6: bcs .gamma_loop + +.finished: rts ; All decompressed! + + ; + ; 1 0 <offset> <length> - gamma-coded LZSS pair. + ; + +.copy_large: jsr .get_gamma ; Bits 8..15 of offset (min 2). + sty <apl_length + 1 ; Clear hi-byte of length. + + cpx #1 ; CC if LWM==0, CS if LWM==1. + sbc #2 ; -3 if LWM==0, -2 if LWM==1. + bcs .normal_pair ; CC if LWM==0 && offset==2. + + jsr .get_gamma ; Get length (A=lo-byte & CC). + ldx <apl_length + 1 + bcc .do_match ; Use previous Offset. + +.normal_pair: sta <apl_offset + 1 ; Save bits 8..15 of offset. + + +APL_GET_SRC + sta <apl_offset + 0 ; Save bits 0...7 of offset. + + jsr .get_gamma ; Get length (A=lo-byte & CC). + ldx <apl_length + 1 + + ldy <apl_offset + 1 ; If offset < 256. + beq .lt256 + cpy #$7D ; If offset >= 32000, length += 2. + bcs .match_plus2 + cpy #$05 ; If offset >= 1280, length += 1. + bcs .match_plus1 + bcc .do_match +.lt256: ldy <apl_offset + 0 ; If offset < 128, length += 2. + bmi .do_match + + sec ; aPLib gamma returns with CC. + +.match_plus2: adc #1 ; CS, so ADC #2. + bcs .match_plus256 + +.match_plus1: adc #0 ; CS, so ADC #1, or CC if fall + bcc .do_match ; through from .match_plus2. + +.match_plus256: inx + +.do_match: eor #$FF ; Negate the lo-byte of length + tay ; and check for zero. + iny + beq .calc_addr + eor #$FF + + inx ; Increment # of pages to copy. + + clc ; Calc destination for partial + adc <apl_dstptr + 0 ; page. + sta <apl_dstptr + 0 + bcs .calc_addr + dec <apl_dstptr + 1 + +.calc_addr: sec ; Calc address of match. + lda <apl_dstptr + 0 + sbc <apl_offset + 0 + sta <apl_winptr + 0 + lda <apl_dstptr + 1 + sbc <apl_offset + 1 + sta <apl_winptr + 1 + +.copy_page: lda (apl_winptr),y + sta (apl_dstptr),y + iny + bne .copy_page + inc <apl_winptr + 1 + inc <apl_dstptr + 1 + dex ; Any full pages left to copy? + bne .copy_page + + inx ; LWM=1. + jmp .next_tag + + ; + ; Subroutines for byte & bit handling. + ; + +.load_bit: +APL_GET_SRC ; Reload an empty bit-buffer + rol ; from the compressed source. + sta <apl_bitbuf + rts diff --git a/tools/apultra/asm/6502/aplib_6502_b.asm b/tools/apultra/asm/6502/aplib_6502_b.asm new file mode 100644 index 0000000..7963e02 --- /dev/null +++ b/tools/apultra/asm/6502/aplib_6502_b.asm @@ -0,0 +1,218 @@ +; ----------------------------------------------------------------------------- +; aplib_6502_b.s - fast aPLib backward decompressor for 6502 - 253 bytes +; written for the ACME assembler +; +; jsr apl_decompress to unpack data backwards. +; create backwards compressed data with apultra -b or oapack -b +; +; in: +; * apl_srcptr (low and high byte) = last byte of compressed data +; * apl_dstptr (low and high byte) = last byte of decompression buffer +; +; out: +; * apl_dstptr (low and high byte) = first byte of decompressed data +; +; Copyright (C) 2020 Emmanuel Marty +; With parts of the code inspired by John Brandwood, Peter Ferrie +; +; 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. +; ----------------------------------------------------------------------------- + + ; Zero page locations + +apl_gamma2_hi = $F6 +apl_bitbuf = $F7 +apl_offset = $F8 +apl_winptr = $FA +apl_srcptr = $FC +apl_dstptr = $FE + + ; Read a byte from the source into A. Trashes X + + !macro APL_GET_SRC { + lda (apl_srcptr),y + ldx <apl_srcptr+0 + bne .src_page_done + dec <apl_srcptr+1 +.src_page_done: dec <apl_srcptr+0 + } + + ; Write a byte to the destinatipn + + !macro APL_PUT_DST { + sta (apl_dstptr),y + lda <apl_dstptr+0 + bne .dst_page_done + dec <apl_dstptr+1 +.dst_page_done: dec <apl_dstptr+0 + } + + ; Read one bit from the source into the carry, trash A + + !macro APL_GET_BIT { + asl <apl_bitbuf + bne .has_bits + jsr apl_load_bits +.has_bits: + } + + ; Read one bit from the source into the carry, preserve A + + !macro APL_GET_BIT_SAVEA { + asl <apl_bitbuf + bne .has_bits + pha + jsr apl_load_bits + pla +.has_bits: + } + + ; Decompress aPLib data backwards + +apl_decompress: lda #$80 ; initialize empty bit queue + sta <apl_bitbuf ; plus bit to roll into carry + ldy #$00 ; clear Y for indirect addr + +.copy_literal: +APL_GET_SRC ; read literal from source +.write_literal: +APL_PUT_DST ; write literal to destination + + ldx #$00 ; clear 'follows match' flag + +.next_token: +APL_GET_BIT ; read 'literal or match' bit + bcc .copy_literal ; if 0: literal + + +APL_GET_BIT ; read '8+n bits or other' bit + bcc .long_match ; if 10x: long 8+n bits match + + ; 11x: other type of match + + +APL_GET_BIT ; read '7+1 match or short literal' bit + bcs .short_match ; if 111: 4 bit offset for 1-byte copy + + +APL_GET_SRC ; read low byte of offset + length bit + lsr ; shift offset into place, len bit into carry + beq .done ; check for EOD + sta <apl_offset+0 ; store low byte of offset + sty <apl_offset+1 ; set high byte of offset to 0 + + tya ; set A to 0 + sty <apl_gamma2_hi ; set high byte of len to 0 + adc #$02 ; add 2 or 3 depending on len bit in carry + ; now, low part of len is in A + ; high part of len in apl_gamma2_hi is 0 + ; offset is written to apl_offset + bne .got_len ; go copy matched bytes + +.long_match: jsr .get_gamma2 ; 10: read gamma2 high offset bits in A + sty <apl_gamma2_hi ; zero out high byte of gamma2 + + cpx #$01 ; set carry if following literal + sbc #$02 ; substract 3 if following literal, 2 otherwise + bcs .no_repmatch + + jsr .get_gamma2 ; read repmatch length: low part in A + bcc .got_len ; go copy large match + ; (carry is always clear after .get_gamma2) + +.short_match: lda #$10 ; clear offset, load end bit into place +.read_short_offs: +APL_GET_BIT_SAVEA ; read one bit of offset into carry + rol ; shift into A, shift end bit as well + bcc .read_short_offs ; loop until end bit is shifted out into carry + + beq .write_literal ; zero offset means write a 0 + tay + lda (apl_dstptr),y ; load backreferenced byte + ldy #$00 ; clear Y again + beq .write_literal ; go write byte to destination + +.get_gamma2: lda #$01 ; 1 so it gets shifted to 2 +.gamma2_loop: +APL_GET_BIT_SAVEA ; read data bit + rol ; shift into low byte + rol <apl_gamma2_hi ; shift into high byte + +APL_GET_BIT_SAVEA ; read continuation bit + bcs .gamma2_loop ; loop until a zero continuation bit is read +.done: rts + +.no_repmatch: sta <apl_offset+1 ; write high byte of offset + +APL_GET_SRC ; read low byte of offset from source + sta <apl_offset+0 ; store low byte of offset + + jsr .get_gamma2 ; read match length: low part in A + + ldx <apl_offset+1 ; high offset byte is zero? + beq .offset_1byte ; if so, offset < 256 + + ; offset is >= 256. + + cpx #$7d ; offset >= 32000 (7d00) ? + bcs .offset_incby2 ; if so, increase match len by 2 + cpx #$05 ; offset >= 1280 (0500) ? + bcs .offset_incby1 ; if so, increase match len by 1 + bcc .got_len ; length is fine, go copy + +.offset_1byte: ldx <apl_offset+0 ; offset < 128 ? + bmi .got_len ; if so, increase match len by 2 + sec ; carry must be set below + +.offset_incby2: adc #$01 ; add 1 + set carry (from bcs or sec) + bcs .len_inchi ; go add 256 to len if overflow + + ; carry clear: fall through for no-op + +.offset_incby1: adc #$00 ; add 1 + carry + bcc .got_len +.len_inchi: inc <apl_gamma2_hi ; add 256 to len if low byte overflows + +.got_len: tax ; transfer low byte of len into X + beq .add_offset + inc <apl_gamma2_hi + +.add_offset: clc ; add dest + match offset + lda <apl_dstptr+0 ; low 8 bits + adc <apl_offset+0 + sta <apl_winptr+0 ; store back reference address + lda <apl_dstptr+1 ; high 8 bits + adc <apl_offset+1 + sta <apl_winptr+1 ; store high 8 bits of address + +.copy_match_loop: lda (apl_winptr),y ; read one byte of backreference + +APL_PUT_DST ; write byte to destination + + lda <apl_winptr+0 ; decrement backreference address + bne .backref_page_done + dec <apl_winptr+1 +.backref_page_done: + dec <apl_winptr+0 + + dex ; loop to copy all matched bytes + bne .copy_match_loop + dec <apl_gamma2_hi + bne .copy_match_loop + + ; X is 0 when exiting the loop above + inx ; set 'follows match' flag + jmp .next_token ; go decode next token + +apl_load_bits: lda (apl_srcptr),y ; read 8 bits from source + rol ; shift bit queue, and high bit into carry + sta <apl_bitbuf ; save bit queue + + lda <apl_srcptr+0 + bne .bits_page_done + dec <apl_srcptr+1 +.bits_page_done: dec <apl_srcptr+0 + rts |