A2osX/LIB/LIBPAK.S.txt

616 lines
13 KiB
Plaintext
Raw Normal View History

PR#3
PREFIX /A2OSX.SRC
NEW
INC 1
AUTO 6
.LIST OFF
.OP 65C02
.OR $2000
.TF /A2OSX.BOOT/LIB/LIBPAK.O
*--------------------------------------
.INB /A2OSX.DEV/INC/MACROS.I
.INB /A2OSX.DEV/INC/A2OSX.I
*--------------------------------------
S.Pak.SrcPtr .EQ ZPLIB
S.Pak.SrcBlPtr .EQ ZPLIB+2
S.Pak.SrcBlPtrT .EQ ZPLIB+4
S.Pak.DstPtr .EQ ZPLIB+6
*--------------------------------------
* File Header (16 Bytes)
*--------------------------------------
CS.START cld
jmp (.1,x)
.DA #$61 6502,Level 1 (65c02)
.DA #1 BIN Layout Version 1
.DA 0
.DA CS.END-CS.START
.DA 0
.DA 0
.DA 0
*--------------------------------------
* Relocation Table
*--------------------------------------
.1 .DA LIB.LOAD
.DA LIB.UNLOAD
.DA Pak
.DA Unpak
.DA 0
*--------------------------------------
LIB.LOAD
LIB.UNLOAD clc
rts
*--------------------------------------
* UNPACK code as short as possible
* For Self Extract
*--------------------------------------
* File Header :
* SFX :
* - BIN must begin with CLD (QCODE)
* - BIN must be relocatable
* - BIN must overwrite itself
* (well, best way is moving CODE to $200)
*--------------------------------------
* Shunk Header :
* WORD : !Target Length
* USED TO STOP UNPACK
* !!!NO EOF TOKEN!!!
* Short4 : [0..15]
* Short3 : [0..7]
*--------------------------------------
S.PAK.LEN .EQ 0
S.PAK.SHORT4 .EQ 2
S.PAK.SHORT3 .EQ 18
S.PAK .EQ 26
*--------------------------------------
* BITSTREAM :
* 0 = STORE :
* 00 : 1 byte follow (10 bits)
* 01 = 2 + n (4 bits count)
*--------------
* 1 = CMD :
*---SHORT4 --- (3)+4=7 bits --------
* 100 : SHORT4
* xxxx = index in Short4 Table
*---SHORT3 --- (3)+3=6 bits --------
* 101 : SHORT3
* xxx = index in Short3 Table
*--- BACKLINK : (3)+8+5=16 bits ----
* 110 : BackLink
* 9 bits : Offset (LO8,HI1)
* 4 bits : 3 + n (4 bits count) (18 max)
*--- REP : (3)+1, (3)+1+4 =4/8 bits ----
* 111 : REP
* 0 : repeat last byte
* 1 : repeat 2 + n (4 bits count)
*--------------------------------------
* In :
* PULLW = Src PTR
* PULLW = Src LEN
* PULLW = Dst PTR Compressed Buffer
*--------------------------------------
PIPELEN .EQ 18
STATS.SIZE .EQ 0
STATS.BL .EQ 2
STATS.REP .EQ 4
STATS.S3 .EQ 6
STATS.S4 .EQ 8
*--------------------------------------
S.Pak >PULLYA
>STYA S.Pak.Src Init for pass #1
>STYA S.Pak.SrcPtr
>PULLA Get Src Len LO
eor #$ff
sta S.Pak.SrcCnt
sta S.Pak.Cnt Init for pass #1
tax
>PULLA Get Src Len HI
eor #$ff
sta S.Pak.SrcCnt+1
sta S.Pak.Cnt+1 Init for pass #1
tay
>PULLW S.Pak.DstPtr
txa
jsr S.Pak.PutByte
tya
jsr S.Pak.PutByte
ldx #9
.1 stz S.Pak.Stat.Size,x Reset Stats
dex
bpl .1
* PASS #1 : Count occurence for each value...
S.Pak.1 ldx #0
.1 stz S.Pak.CntL,x
stz S.Pak.CntH,x
inx
bne .1
ldy #0
.2 inc S.Pak.Cnt
bne .3
inc S.Pak.Cnt+1
beq .5
.3 lda (S.Pak.SrcPtr),y
tax
inc S.Pak.CntL,x
bne .4
inc S.Pak.CntH,x
.4 iny
bne .2
inc S.Pak.SrcPtr+1
bra .2
* ...Search for Top 24
.5 ldy #23
.6 stz S.Pak.Cnt Init best score to 0
stz S.Pak.Cnt+1
stz S.Pak.Byte
ldx #0
.7 lda S.Pak.CntL,x is it better at X
cmp S.Pak.Cnt
lda S.Pak.CntH,x
sbc S.Pak.Cnt+1
bcs .8 not better
stx S.Pak.Byte
lda S.Pak.CntL,x
sta S.Pak.Cnt
lda S.Pak.CntH,x
sta S.Pak.Cnt+1
.8 inx
bne .7
lda S.Pak.Byte
sta S.Pak.Short,y
stz S.Pak.CntL,x Discard this entry
stz S.Pak.CntH,x
dey
bpl .6
ldx #15
.9 lda S.Pak.Short4,x Store SHORT4 in reverse order
jsr S.Pak.PutByte
dex
bpl .9
ldx #7
.10 lda S.Pak.Short3,x Store SHORT3 in reverse order
jsr S.Pak.PutByte
dex
bpl .10
>LDYAI S.PAK Total Header Size
>STYA S.Pak.Stat.Size
* PASS #2 :
S.Pak.2 >LDYA S.Pak.Src Init for pass #2
>STYA S.Pak.SrcPtr
>STYA S.Pak.SrcBlPtr
>LDYA S.Pak.SrcCnt
>STYA S.Pak.Cnt
lda #8
sta S.Pak.PutBit+1 Initialize properly for first "PutBit" Call
stz S.Pak.Byte
stz S.Pak.PipeLen
S.Pak.2.LOOP ldx S.Pak.PipeLen Always fill Bytes in the PIPE until full
.1 jsr S.Pak.GetByte Load PIPE....
bcs .2 end of Buffer ?
sta S.Pak.Pipe,x
inx
cpx #PIPELEN PIPE Full ?
bne .1
clc
.2 stx S.Pak.PipeLen
txa PIPE empty ....exit
beq .99
* try finding REPeating same bytes.....
S.Pak.2.REP dex
beq S.Pak.2.SHORT Only one char in PIPE...
ldx #0
.1 lda S.Pak.Pipe,x
cmp S.Pak.Pipe+1,x
bne .2
inx
cpx S.Pak.PipeLen
bne .1
.2 dex if one char.....no REP
beq .S.Pak.2.BL
dex if 2, -> REP ONE (not 2)
phx REP 1 + 0 or more....save REP count for later....
jsr S.Pak.2.STORE1 a = byte to store
lda #%11100000
plx
phx
beq .3
ora #%00010000
ldy #4
jsr S.Pak.PutYBits
txa
beq .4 if not REP 2 or more no extra count
ldy #4
jsr S.Pak.PutYBits
.4 pla
clc
adc #2
tay
jsr S.Pak.StripPipe Remove REP bytes from PIPE
ldy #STATS.REP
jsr S.Pak.UpdateStats
jmp S.Pak.2.LOOP
S.Pak.2.BL
* Try finding best matching BackLink between SrcBlPtr and SrcPtr (max 512)
.4 lda S.Pak.SrcPtr
sec
sbc S.Pak.PipeLen
sta S.Pak.Limit setup Limit to SrcPtr-PIPE
lda S.Pak.SrcPtr+1
sbc #0
sta S.Pak.Limit+1
.40 lda S.Pak.SrcBlPtr
sta S.Pak.SrcBlPtrT
lda S.Pak.SrcBlPtr+1
sta S.Pak.SrcBlPtrT+1
.5 txa Get PIPE Len
clc make sure SrcBlPtrT+PIPE < Limit
adc S.Pak.SrcBlPtrT
tay
lda S.Pak.SrcBlPtrT+1
adc #0
cpy S.Pak.Limit
sbc S.Pak.Limit+1
bcc .10 not enough room
txa
dec
tay
.8 lda (S.Pak.SrcBlPtrT),y
cmp S.Pak.Pipe,y
bne .9
dey
bpl .8
* Found a BL at S.Pak.SrcBlPtrT, Store it and remove X bytes from PIPE
phx save BL length
lda #%1100000
ldy #3
jsr S.Pak.PutYBits
lda S.Pak.Limit
sec
sbc S.Pak.SrcBlPtrT
php save C
ldy #8
jsr S.Pak.PutYBits
plp
lda S.Pak.Limit+1
sec
sbc S.Pak.SrcBlPtrT+1
jsr S.Pak.PutBit
ply Get back BL len
phy
jsr S.Pak.StripPipe Remove LEN bytes from PIPE
pla Get back BL len
sec
sbc #3 Adjust Range..3-18 to 0->15
asl
asl
asl
asl
ldy #4 store 4 bits len
jsr S.Pak.PutYBits
ldy #STATS.BL
jsr S.Pak.UpdateStats
jmp S.Pak.2.LOOP
* No match...try starting at next byte
.9 inc S.Pak.SrcBlPtrT
bne .5
inc S.Pak.SrcBlPtrT+1
bra .5
.10 dex reduce PIPE
cpx #2 2 bytes remaining? no need to BL, a BL is 16bits wide.....
bne .40 and start over from BLPtr
* NO Bl Found, STORE
S.Pak.STORE lda S.Pak.Pipe
jsr S.Pak.2.STORE1
ldy #1
jsr S.Pak.StripPipe
jmp S.Pak.2.LOOP
*--------------------------------------
S.Pak.2.STORE1
rts
*--------------------------------------
S.Pak.GetByte inc S.UnPak.Cnt
bne .1
inc S.UnPak.Cnt+1
.1 beq .9
lda (S.Pak.SrcPtr)
pha
inc S.Pak.SrcPtr
bne .2
inc S.Pak.SrcPtr+1
.2 clc
rts
.9 sec
rts
*--------------------------------------
S.Pak.PutYBits asl
jsr S.Pak.PutBit
dey
bne S.Pak.PutYBits
rts
*--------------------------------------
* S.Pak.PutBit (bit in C)
*--------------------------------------
S.Pak.PutBit ldx #$ff
pha
bne .1
lda S.Pak.Byte
jsr S.Pak.PutByte
stz S.Pak.Byte
ldx #8
.1 dex
stx S.Pak.PutBit+1
bcc .8 Nothing to "light up"
lda S.Pak.Byte
lda S.Pak.BitMask,x
sta S.Pak.Byte
.8 pla
rts
*--------------------------------------
S.Pak.PutByte sta (S.UnPak.DstPtr)
inc S.UnPak.DstPtr
bne .1
inc S.UnPak.DstPtr+1
.1 inc S.Pak.Stat.Size
bne .2
inc S.Pak.Stat.Size+1
.2
rts
*--------------------------------------
* Y = count to remove from PIPE
*--------------------------------------
S.Pak.StripPipe ldx S.Pak.PipeLen
beq .9
ldx #0
.1 lda S.Pak.Pipe+1,x
sta S.Pak.Pipe,x
inx
cpx S.Pak.PipeLen
bne .1
dec S.Pak.PipeLen
dey
bne S.Pak.StripPipe
.9 rts
*--------------------------------------
S.Pak.UpdateStats
inc S.Pak.Stat.Size,y
bne .8
inc S.Pak.Stat.Size+1,y
.8 rts
*--------------------------------------
S.Pak.BitMask .HS 0102040810204080
S.Pak.Src .BS 2
S.Pak.SrcCnt .BS 2
S.Pak.Cnt .BS 2
S.Pak.CntL .BS 256
S.Pak.CntH .BS 256
S.Pak.Short4 .BS 16
S.Pak.Short3 .BS 8
S.Pak.Byte .BS 1
S.Pak.Limit .BS 2
S.Pak.PipeLen .BS 1
S.Pak.Pipe .BS 18
*--------------------------------------
S.Pak.Stat.Size .BS 2
S.Pak.Stat.BL .BS 2
S.Pak.Stat.REP .BS 2
S.Pak.Stat.S3 .BS 2
S.Pak.Stat.S4 .BS 2
*--------------------------------------
* S.UnPak
* In :
* PULLW = Src PTR Compressed Buffer
* PULLW = Dst PTR
*--------------------------------------
S.UnPak.SrcPtr .EQ ZPLIB
S.UnPak.DstPtr .EQ ZPLIB+2
S.UnPak.ShrtTbl .EQ ZPLIB+4
S.UnPak.Cnt .EQ ZPLIB+6
*--------------------------------------
S.UnPak >PULLW S.UnPak.SrcPtr
>PULLA Get Dst PTR LO
sec
sbc #1
sta S.UnPak.DstPtr
>PULLA Get Dst PTR HI
sbc #0
sta S.UnPak.DstPtr+1 setup Dst PTR-1
jsr S.UnPak.GetByte Get !LEN for counting up to $0000
sta S.UnPak.Cnt
jsr S.UnPak.GetByte
sta S.UnPak.Cnt+1
>LDYA S.UnPak.SrcPtr Get PTR to Short Table.....
>STYA S.UnPak.ShrtTbl and save it for SHORTx
lda #8
sta S.UnPak.GetBit+1 Initialize properly for first "GetBit" Call
.1 inc S.UnPak.Cnt
bne .2
inc S.UnPak.Cnt+1
beq .99
.2 jsr S.UnPak.GetBit
bcs .4 CMD....
*---- STORE
jsr S.UnPak.GetBit
ldx #1
bcc .3 if CC one byte
jsr S.UnPak.Get4Bits CC
adc #2 range is 2->17
tax
.3 jsr S.UnPak.Get8Bits
jsr S.UnPak.PutByte
dex
bne .3
bra .1
.99 rts
*---- CMD
.4 jsr S.UnPak.GetBit
bcs .6 BACKLINK or REP...
*---- CMD : SHORT
lda #0
ldy #4
jsr S.UnPak.GetBit if CS short3
rol make offset 00000001
asl ....00000010
beq .5
dey if short3, only 3 bits
.5 jsr S.UnPak.GetBit
rol
dey
bne .5
tay if s3, offset is 00010xxx
lda (S.UnPak.ShrtTbl),y if s4, offset is 0000xxxx
jsr S.UnPak.PutByte
bra .1
*---- CMD : BACKLINK or REP
.6 jsr S.UnPak.GetBit
bcs .8 if CS -> REP
*---- CMD : BACKLINK
jsr S.UnPak.Get8Bits get Offset LO, (CC)
eor #$ff !offset LO
adc S.UnPak.DstPtr equiv. SUB offset
sta .7+1 PTR to Backlink LO
lda S.UnPak.DstPtr+1
bcs .61 if ADC sets C, no need to dec HI
dec
.61 jsr S.UnPak.GetBit get Offset HI in C
bcc .62
dec
.62 sta .7+2 PTR to Backlink HI
jsr S.UnPak.Get4Bits CC
adc #3 Backlink are ate least 3 bytes...
tax
ldy #0
.7 lda $ffff,y Self Modified code : PTR to Backlink
jsr S.UnPak.PutByte
iny
dex
bne .7
beq .1
*---- CMD : REP
.8 jsr S.UnPak.GetBit
ldx #1
bcc .9 REP 1
jsr S.UnPak.Get4Bits REP xxxx, CC
adc #2 range is 2->17
tax
.9 lda (S.UnPak.DstPtr) Get Last Byte
jsr S.UnPak.PutByte
dex
bne .9
beq .1
*--------------------------------------
S.UnPak.Get8Bits
ldy #8
.HS 2C bit abs
S.UnPak.Get4Bits
ldy #4
lda #0 make sure to reset A before reading less than 8 bits only
.1 jsr S.UnPak.GetBit and to exit with CC if even if 8 bits read
rol
dey
bne .1
rts always CC
*--------------------------------------
S.UnPak.GetBit ldx #$ff Self Modified code
bne .1
jsr S.UnPak.NxtByte
ldx #8
.1 dex
stx S.UnPak.GetBit+1
pha Don't trash A
lda (S.UnPak.SrcPtr)
and S.UnPak.BitMask,x
cmp #1 if 0:CC, i>0 CS
pla
rts Bit is in C
*--------------------------------------
S.UnPak.GetByte lda (S.UnPak.SrcPtr)
S.UnPak.NxtByte inc S.UnPak.SrcPtr
bne .8
inc S.UnPak.SrcPtr+1
.8 rts
*--------------------------------------
S.UnPak.PutByte inc S.UnPak.DstPtr
bne .8
inc S.UnPak.DstPtr+1
.8 sta (S.UnPak.DstPtr)
rts
*--------------------------------------
S.UnPak.BitMask .HS 8040201008040201
MAN
SAVE LIB/LIBPAK.S
ASM