Jump to content



Recommended Posts

Ok I need some help. I found a really good compression routine for the C64. The compressor is on the PC and the decompressor is in ASM for C64. It looks very feasible to use this but I have been trying to set it up and it'll only decompress about 4 bytes until it goes stupid and starts spewing garbage I'm not sure where I am going wrong here.


Can anyone that is better at ASM than I am take a quick look at this program and see what they think? I talked to the original programmer so I know it does need to run out of RAM since it self-modifies. I would be glad to chat on the developers board about it and see what we can work out on it.


The address for the program is Pucrunch. Also the designer said I was trying to do something similar to what he did with his Vimm demo in the Vicpic part. Address for info on this is Vimm.


This is a major stumbling block for me and the further progress of Adventure 2. I have spent a week fighting with this. I would post the code I was using but it would be nasty spaghetti code because the original program is DASM and I use TASM and I put a lot of it in as .byte includes so would be useless for error detecting. At this point it would be better to get a fresh start and some help. Thanks again,


Link to comment
Share on other sites

The assembler code looks very straight forward and there are only a few places where selfmodifying code is used. In most cases, changing the code into indirect access would solve the problem without to much performance loss.





INPOS = *+1

lda $aaaa

change into



INPOS .word


ldy #0

lda (INPOS),y


And perhaps you have to save and restore Y.


[ 03-11-2002: Message edited by: Thomas Jentzsch ]

Link to comment
Share on other sites

The code seemed to compile without a problem and the run from RAM was fine. Where I hit problems was when I tried to decompress a screen. There were 4 bytes that uncompressed fine then the last two should have been repeated say 10 times. At that point it just spit out garbage. I think there is an error somewhere in the LZW decompression routine but I can't find it unfortunately. Not sure where it went wrong.


Also it seems the first two bytes of the header of the compressed file are never read off anywhere. Not sure why they are there either. I would really love to get this working since out of two screens I compressed I ended up averaging about 20% of original file size which is better than I hoped for.


Link to comment
Share on other sites

Ok I finally managed to find a few errors so it tries a little more but still only gets 4 bytes into the decompression and screws up. I can post more if needed. Just tell me what you need. I found a few errors such as every #$00 in the original file compiled as a #$20 which is simply an issue with me and DASM as I think that is where the error occured. The other error was in my copy routine when I move it to RAM at $1500. I was rolling my loop wrong and was missing $15FF. I fixed that. I did a byte for byte compare and now $1500 is storing exactly what is stored in the ROM at $b000 ($7000 in this disassemly as it doesn't accout for the beginning of the ROM being at $4000). Any help you guys can offer would be greatly appreciated,




ORG $1500



; Call with X = HI of packed data, Y = LO of packed data

; Returns exec address in X = HI and Y = LO

; Carry will be set for error, cleared for OK


sty INPOS ; Setup read pointer


stx INPOS+1


jsr getbyt ; 'p'

jsr getbyt ; 'u'

jsr getbyt ; skip endAddr

jsr getbyt

jsr getbyt

sta esc+1 ; starting escape


jsr getbyt ; read startAddr


jsr getbyt

sta OUTPOS+1


jsr getbyt ; read # of escape bits

sta escB0+1

sta escB1+1

lda #8


sbc escB1+1

sta noesc+1 ; 8-escBits


jsr getbyt

sta mg+1 ; maxGamma + 1

lda #9


sbc mg+1 ; 8 - maxGamma == (8 + 1) - (maxGamma + 1)

sta longrle+1

jsr getbyt

sta mg1+1 ; (1<



sbc #0

sta mg21+1 ; (2<

jsr getbyt

sta elzpb+1


jsr getbyt ; exec address

sta lo+1 ; lo

jsr getbyt

sta hi+1 ; hi


jsr getbyt ; rleUsed

ldx #0


t1 beq t2 ; Y == 0 ?

jsr getbyt

sta rletabl,x



bne t1

t2 lda #$80 ; setup bit store - $80 means empty

sta bitstr+1

jmp main


getbyt jsr getnew

bitstr lda #0





newesc ldy esc+1 ; remember the old code (top bits for escaped byte)

escB0 ldx #2 ; ** PARAMETER 0..8

jsr getchkf ; get & save the new escape code

sta esc+1

tya ; pre-set the bits

; Fall through and get the rest of the bits.

noesc ldx #6 ; ** PARAMETER 8..0

jsr getchkf

jsr putch ; output the escaped/normal byte

; Fall through and check the escape bits again

main ldy #0 ; Reset to a defined state

tya ; A = 0

escB1 ldx #2 ; ** PARAMETER 0..8

jsr getchkf ; X = 0

esc cmp #0

bne noesc

; Fall through to packed code


jsr getval ; X = 0

sta LZPOS+1 ; xstore - save the length for a later time

lsr ; cmp #1 ; LEN == 2 ? (A is never 0)

bne lz77 ; LEN != 2 -> LZ77

;tya ; A = 0

jsr get1bit ; X = 0

lsr ; bit -> C, A = 0

bcc lz77_2 ; A=0 -> LZPOS+1

;***FALL THRU***


; e..e01

jsr get1bit ; X = 0

lsr ; bit -> C, A = 0

bcc newesc ; e..e010

;***FALL THRU***


; e..e011

srle iny ; Y is 1 bigger than MSB loops

jsr getval ; Y is 1, get len, X = 0

sta LZPOS+1 ; xstore - Save length LSB

mg1 cmp #64 ; ** PARAMETER 63-64 -> C clear, 64-64 -> C set..

bcc chrcode ; short RLE, get bytecode


longrle ldx #2 ; ** PARAMETER 111111xxxxxx

jsr getbits ; get 3/2/1 more bits to get a full byte, X = 0

sta LZPOS+1 ; xstore - Save length LSB


jsr getval ; length MSB, X = 0

tay ; Y is 1 bigger than MSB loops


chrcode jsr getval ; Byte Code, X = 0

tax ; this is executed most of the time anyway

lda rletabl-1,x ; Saves one jump if done here (loses one txa)


cpx #32 ; 31-32 -> C clear, 32-32 -> C set..

bcc t3 ; 1..31, we got the right byte from the table


; Ranks 32..64 (11111°xxxxx), get byte..

txa ; get back the value (5 valid bits)

ldx #3

jsr getbits ; get 3 more bits to get a full byte, X = 0


t3 ldx LZPOS+1 ; xstore - get length LSB

inx ; adjust for cpx#$ff;bne -> bne

dorle jsr putch


bne dorle ; xstore 0..255 -> 1..256


bne dorle ; Y was 1 bigger than wanted originally

mainbeq beq main ; reverse condition -> jump always



lz77 jsr getval ; X = 0

mg21 cmp #127 ; ** PARAMETER Clears carry (is maximum value)

bne noeof


hi ldx #0

lo ldy #0




noeof sbc #0 ; C is clear -> subtract 1 (1..126 -> 0..125)

elzpb ldx #0 ; ** PARAMETER (more bits to get)

jsr getchkf ; clears Carry, X = 0


lz77_2 sta LZPOS+2 ; offset MSB

jsr getbyte ; clears Carry, X = 0

; Note: Already eor:ed in the compressor..

;eor #255 ; offset LSB 2's complement -1 (i.e. -X = ~X+1)

adc OUTPOS ; -offset -1 + curpos (C is clear)

ldx LZPOS+1 ; xstore = LZLEN (read before it's overwritten)

sta LZPOS+1


lda OUTPOS+1

sbc LZPOS+2 ; takes C into account

sta LZPOS+2 ; copy X+1 number of chars from LZPOS to OUTPOS

;ldy #0 ; Y was 0 originally, we don't change it


inx ; adjust for cpx#$ff;bne -> bne


LZPOS lda $aaaa,y

jsr putch ; Note: must be copied forwards!

iny ; Y does not wrap because X=0..255 and Y initially 0


bne lzloop ; X loops, (256,1..255)

beq mainbeq ; jump through another beq (-1 byte, +3 cycles)



getnew pha ; 1 Byte/3 cycles

INPOS = *+1

lda $aaaa ; ** PARAMETER


bne t4

inc INPOS+1

t4 sec

rol ; Shift out the next bit and

; shift in C=1 (last bit marker)

sta bitstr+1 ; bitstr initial value = $80 == empty

pla ; 1 Byte/4 cycles


; 25+12 = 37


; getval : Gets a 'static huffman coded' value

; ** Scratches X, returns the value in A **

getval inx ; X <- 1

txa ; set the top bit (value is 1..255)

gv0 asl bitstr+1

bne t5

jsr getnew

t5 bcc getchk ; got 0-bit


mg cpx #7 ; ** PARAMETER unary code maximum length + 1

bne gv0

beq getchk ; inverse condition -> jump always

; getval: 18 bytes

; 15 + 17*n + 6+15*n+12 + 36*n/8 = 33 + 32*n + 36*n/8 cycles


; getbits: Gets X bits from the stream

; ** Scratches X, returns the value in A **

getbyte ldx #7

get1bit inx ;2

getbits asl bitstr+1

bne t6

jsr getnew

t6 rol ;2

getchk dex ;2 more bits to get ?

getchkf bne getbits ;2/3

clc ;2 return carry cleared

rts ;6+6



OUTPOS = *+1 ; ZP

putch sta $aaaa ; ** parameter


bne t7

inc OUTPOS+1 ; ZP

t7 rts



rletabl .byte 0,0,0,0,0,0,0

.byte 0,0,0,0,0,0,0,0

.byte 0,0,0,0,0,0,0,0

.byte 0,0,0,0,0,0,0,0




here is the disassembly of what ended up in my 5200 bin.



00007000:	8C2B16	STY $162B

00007003: 8E2C16 STX $162C

00007006: 207E15 JSR $157E

00007009: 207E15 JSR $157E

0000700C: 207E15 JSR $157E

0000700F: 207E15 JSR $157E

00007012: 207E15 JSR $157E

00007015: 8DA215 STA $15A2

00007018: 207E15 JSR $157E

0000701B: 8D6116 STA $1661

0000701E: 207E15 JSR $157E

00007021: 8D6216 STA $1662

00007024: 207E15 JSR $157E

00007027: 8D8915 STA $1589

0000702A: 8D9D15 STA $159D

0000702D: A908 LDA #$08

0000702F: 38 SEC

00007030: ED9D15 SBC $159D

00007033: 8D9215 STA $1592

00007036: 207E15 JSR $157E

00007039: 8D4A16 STA $164A

0000703C: A909 LDA #$09

0000703E: 38 SEC

0000703F: ED4A16 SBC $164A

00007042: 8DC615 STA $15C6

00007045: 207E15 JSR $157E

00007048: 8DC215 STA $15C2

0000704B: 0A ASL A

0000704C: 18 CLC

0000704D: E900 SBC #$00

0000704F: 8DF515 STA $15F5

00007052: 207E15 JSR $157E

00007055: 8D2016 STA $1620

00007058: 207E15 JSR $157E

0000705B: 8DFB15 STA $15FB

0000705E: 207E15 JSR $157E

00007061: 8DF915 STA $15F9

00007064: 207E15 JSR $157E

00007067: A200 LDX #$00

00007069: A8 TAY

0000706A: F00A BEQ $0A

0000706C: 207E15 JSR $157E

0000706F: 9D6C16 STA $166C,X

00007072: E8 INX

00007073: 88 DEY

00007074: D0F4 BNE $F4

00007076: A980 LDA #$80

00007078: 8D8215 STA $1582

0000707B: 4C9915 JMP $1599

0000707E: 202916 JSR $1629

00007081: A900 LDA #$00

00007083: 6A ROR A

00007084: 60 RTS

00007085: ACA215 LDY $15A2

00007088: A202 LDX #$02

0000708A: 205C16 JSR $165C

0000708D: 8DA215 STA $15A2

00007090: 98 TYA

00007091: A206 LDX #$06

00007093: 205C16 JSR $165C

00007096: 206016 JSR $1660

00007099: A000 LDY #$00

0000709B: 98 TYA

0000709C: A202 LDX #$02

0000709E: 205C16 JSR $165C

000070A1: C900 CMP #$00

000070A3: D0EC BNE $EC

000070A5: 203C16 JSR $163C

000070A8: 8D1E16 STA $161E

000070AB: 4A LSR A

000070AC: D043 BNE $43

000070AE: 205116 JSR $1651

000070B1: 4A LSR A

000070B2: 9050 BCC $50

000070B4: 205116 JSR $1651

000070B7: 4A LSR A

000070B8: 90CB BCC $CB

000070BA: C8 INY

000070BB: 203C16 JSR $163C

000070BE: 8D1E16 STA $161E

000070C1: C940 CMP #$40

000070C3: 900C BCC $0C

000070C5: A202 LDX #$02

000070C7: 205216 JSR $1652

000070CA: 8D1E16 STA $161E

000070CD: 203C16 JSR $163C

000070D0: A8 TAY

000070D1: 203C16 JSR $163C

000070D4: AA TAX

000070D5: BD6B16 LDA $166B,X

000070D8: E020 CPX #$20

000070DA: 9006 BCC $06

000070DC: 8A TXA

000070DD: A203 LDX #$03

000070DF: 205216 JSR $1652

000070E2: AE1E16 LDX $161E

000070E5: E8 INX

000070E6: 206016 JSR $1660

000070E9: CA DEX

000070EA: D0FA BNE $FA

000070EC: 88 DEY

000070ED: D0F7 BNE $F7

000070EF: F0A8 BEQ $A8

000070F1: 203C16 JSR $163C

000070F4: C97F CMP #$7F

000070F6: D005 BNE $05

000070F8: A200 LDX #$00

000070FA: A000 LDY #$00

000070FC: 60 RTS

000070FD: E900 SBC #$00

000070FF: A200 LDX #$00

00007101: 205C16 JSR $165C

00007104: 8D1F16 STA $161F

00007107: 204F16 JSR $164F

0000710A: 6D6116 ADC $1661

0000710D: AE1E16 LDX $161E

00007110: 8D1E16 STA $161E

00007113: AD6216 LDA $1662

00007116: ED1F16 SBC $161F

00007119: 8D1F16 STA $161F

0000711C: E8 INX

0000711D: B9AAAA LDA $AAAA,Y

00007120: 206016 JSR $1660

00007123: C8 INY

00007124: CA DEX

00007125: D0F6 BNE $F6

00007127: F0C6 BEQ $C6

00007129: 48 PHA


0000712D: EE2B16 INC $162B

00007130: D003 BNE $03

00007132: EE2C16 INC $162C

00007135: 38 SEC

00007136: 2A ROL A

00007137: 8D8215 STA $1582

0000713A: 68 PLA

0000713B: 60 RTS

0000713C: E8 INX

0000713D: 8A TXA

0000713E: 0E8215 ASL $1582

00007141: D003 BNE $03

00007143: 202916 JSR $1629

00007146: 9013 BCC $13

00007148: E8 INX

00007149: E007 CPX #$07

0000714B: D0F1 BNE $F1

0000714D: F00C BEQ $0C

0000714F: A207 LDX #$07

00007151: E8 INX

00007152: 0E8215 ASL $1582

00007155: D003 BNE $03

00007157: 202916 JSR $1629

0000715A: 2A ROL A

0000715B: CA DEX

0000715C: D0F4 BNE $F4

0000715E: 18 CLC

0000715F: 60 RTS

00007160: 8DAAAA STA $AAAA

00007163: EE6116 INC $1661

00007166: D003 BNE $03

00007168: EE6216 INC $1662

0000716B: 60 RTS

0000716C: 00 BRK

0000716D: 00 BRK

0000716E: 00 BRK

0000716F: 00 BRK

00007170: 00 BRK

00's continue on for another 36 bytes or so

Link to comment
Share on other sites

Grrrr Can anyone confirm that some of my jump addresses or self-modifying addresses are off? I'm going thru it line by line now



0000711D: B9AAAA LDA $AAAA,Y

00007120: 206016 JSR $1660

00007123: C8 INY

00007124: CA DEX


That area when I disassemble memory in the 5200 after a partial run when it crashes is showing up as:


B9 02 10 LDA $1002,Y ;looks ok as my screen is $1000

00 BRK ;huh?

60 RTS

16 C8 ASL $C8,X


well you can see that is quite a bit different. Seems something is modifying $1620 which is where that break appeared. Now just to figure out where and why. I think there were some mild problem when I did the assembly which are coming to haunt me Not sure where I went wrong tho.


Link to comment
Share on other sites

Ok that $1620 being modified was the problem. All fixed now. It seems somehow that when my code was put into the source a bunch of the $00 changed to $20. Can you guess that it was supposed to be $1600 being modified and not $1620? Seems I missed one of the screwups. All fixed except it isn't loading in the colors and that is just a modification I need to do from when I began the changeover to compression. Thanks for everyone's help!


  • Like 1
Link to comment
Share on other sites

  • 1 month later...
  • 19 years later...

Did you ever get this to work (18 years ago!)? I tried the code you posted here and didn't get very far. It compiles but crashes. I'm including a binary file that I compressed with pucrunch (-d -c0) and trying to pass in the address in X/Y but it hangs. If you have working source you could share I'd much appreciate it --- just starting to learn my way around a8/6502

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...