Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
MegaLZ depacker
#1
I was using MegaLZ, and I figured it worth listing how to make it a SUB.

Trivially easy, actually - it's provided as ASM source. There's a windows binary program to compress data. Just call this like a mem copy, with source (packed data) and destination (for unpacked data).

I've used it to pack down screen data, and just unpacked it to the screen - it's slow enough to be visible, so do it with attributes set to invisible, and the user won't notice.


Code:
SUB megaLZDepack (source as uInteger, dest as uInteger) ASM LD E,(IX+6) LD D,(IX+7) ;Z80 depacker for megalz V4 packed files (C) fyrex^mhm ; DESCRIPTION: ; ; Depacker is fully relocatable, not self-modifying, ;it's length is 110 bytes starting from DEC40. ;Register usage: AF,AF',BC,DE,HL. Must be CALL'ed, return is done by RET. ;Provide extra stack location for store 2 bytes (1 word). Depacker does not ;disable or enable interrupts, as well as could be interrupted at any time ;(no f*cking wicked stack usage :). ; USAGE: ; ; - put depacker anywhere you want, ; - put starting address of packed block in HL, ; - put location where you want data to be depacked in DE, ; (much like LDIR command, but without BC) ; - make CALL to depacker (DEC40). ; - enjoy! ;) ; PRECAUTIONS: ; ; Be very careful if packed and depacked blocks coincide somewhere in memory. ;Here are some advices: ; ; 1. put packed block to the highest addresses possible. ; Best if last byte of packed block has address #FFFF. ; ; 2. Leave some gap between ends of packed and depacked block. ; For example, last byte of depacked block at #FF00, ; last byte of packed block at #FFFF. ; ; 3. Place nonpackable data to the end of block. ; ; 4. Always check whether depacking occurs OK and neither corrupts depacked data ; nor hangs computer. ; ;DEC40 LD A,80h EX AF,AF' MS: LDI M0: LD BC,2FFh M1: EX AF,AF' M1X: ADD A,A JR NZ,M2 LD A,(HL) INC HL RLA M2: RL C JR NC,M1X EX AF,AF' DJNZ X2 LD A,2 SRA C JR C,N1 INC A INC C JR Z,N2 LD BC,33Fh JR M1 X2: DJNZ X3 SRL C JR C,MS INC B JR M1 X6: ADD A,C N2: LD BC,4FFh JR M1 N1: INC C JR NZ,M4 EX AF,AF' INC B N5: RR C JP C, END_DEC40 RL B ADD A,A JR NZ,N6 LD A,(HL) INC HL RLA N6: JR NC,N5 EX AF,AF' ADD A,B LD B,6 JR M1 X3: DJNZ X4 LD A,1 JR M3 X4: DJNZ X5 INC C JR NZ,M4 LD BC,51Fh JR M1 X5: DJNZ X6 LD B,C M4: LD C,(HL) INC HL M3: DEC B PUSH HL LD L,C LD H,B ADD HL,DE LD C,A LD B,0 LDIR POP HL JR M0 END_DEC40: END ASM END SUB
Reply
#2
Nice :!:
I'll convert it to fastcall and will pack it with the compiler.

Update: I see you load DE from (IX+n) but not HL? Probably it's working because the compiler uses HL to load addresses and it's already set. But this could crash under some circumnstances. There should be a LD HL, (IX+n) sequence to load HL too.

But better convert it to fascall:
Code:
SUB FASTCALL megaLZDepack (source as uInteger, dest as uInteger) ASM ; HL already loaded (source) ; dest in the stack, before the return address pop bc ; Remove return address pop de ; DE <-- dest address ; NOTE: Remove LD D, (IX+n) and LD E, (IX+n) instructions push bc ; Restores return address ; The remaing code is untouched: ;Z80 depacker for megalz V4 packed files (C) fyrex^mhm ; DESCRIPTION: ; ; Depacker is fully relocatable, not self-modifying, ;it's length is 110 bytes starting from DEC40. ...
Reply
#3
I thought fastcall only worked with one parameter?

Still confused as to how those work!

Anyway, if you can make it fastcall, you can probably do ret c instead of jp c, end_of_subroutine; which makes it tighter. (it originally would have had that).
Reply
#4
britlion Wrote:I thought fastcall only worked with one parameter?

Still confused as to how those work!

Anyway, if you can make it fastcall, you can probably do ret c instead of jp c, end_of_subroutine; which makes it tighter. (it originally would have had that).
FASTCALL can be use with more than one parameter, but only the 1st one will be passed in registers. Remaining ones will be passed in the stack, and the programmer MUST pop them out before returning, or your program could crash, etc.

If you look back to my code, I pop out the 2nd parameter in DE. The problem here is that the return address (used by RET) is always pushed automatically by the CPU on TOP, so you must preserve it (pop it out, pop out your parameters, and push it in again before returning). So this is why I use POP BC, POP DE, PUSH BC sequence (BC = temporary storage here).
Reply
#5
THIS WILL be VERY USEFUL for me... But the problem is the gap between blocks of compressed blocks. I would prefer to have a parameter for length of packed or unpacked data.
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#6
I don't think I understand what you mean there LCD. It sort of is what it is really. Takes compressed data from source and puts it as expanded data at destination. There's no data gap internal to either format.

My use for it at the moment is expanding banners to the first 2k of the screen from compressed version elsewhere.

I think a common use might be setting up a buffer for data, and expanding compressed data to the buffer for use, replacing the buffer contents as new data is required - such as the player moving to a new screen.
Reply
#7
britlion, does the FASTCALL and push pop sequence I put worked for you?
Reply
#8
britlion Wrote:I don't think I understand what you mean there LCD. It sort of is what it is really. Takes compressed data from source and puts it as expanded data at destination. There's no data gap internal to either format.
But how does the dapacker know, how much to depack?
"3. Place nonpackable data to the end of block."
means surely a gap (filled with rubbish), or did I understand it wrong and the size is encoded by compressor in packed data?

Edit: I now understand it!This note is for compressor only if we want to pack multiple data from same file. My fault!!!
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#9
boriel Wrote:britlion, does the FASTCALL and push pop sequence I put worked for you?

No.
I still don't understand this, apparently.

e.g.: function mirror (dowedoit as uByte, number as uByte) as uByte

This gets dowedoit in the A register, and both dowedoit and number in the stack.

Stack seems to be:
return address
<some pair of bytes I can't work out>
first parameter pair
second parameter pair

However, if in the above case I do
pop hl
pop de
pop de
pop bc
push hl
ret

It still seems to behave very strangely.

I know that a first byte parameter is at IX+5 (and IX+4 if it's 16 bit)- so logically it's the return address at IX+0, and IX+1. What's at IX+2,IX+3?
Reply
#10
LCD Wrote:
britlion Wrote:I don't think I understand what you mean there LCD. It sort of is what it is really. Takes compressed data from source and puts it as expanded data at destination. There's no data gap internal to either format.
But how does the dapacker know, how much to depack?
"3. Place nonpackable data to the end of block."
means surely a gap (filled with rubbish), or did I understand it wrong and the size is encoded by compressor in packed data?

Edit: I now understand it!This note is for compressor only if we want to pack multiple data from same file. My fault!!!

Ah yes - LCD. A packed file knows its own length; it's not continuous. You can't unpack part of it without changing the decompression code, there.
Reply
#11
britlion Wrote:
LCD Wrote:
britlion Wrote:I don't think I understand what you mean there LCD. It sort of is what it is really. Takes compressed data from source and puts it as expanded data at destination. There's no data gap internal to either format.
But how does the dapacker know, how much to depack?
"3. Place nonpackable data to the end of block."
means surely a gap (filled with rubbish), or did I understand it wrong and the size is encoded by compressor in packed data?

Edit: I now understand it!This note is for compressor only if we want to pack multiple data from same file. My fault!!!

Ah yes - LCD. A packed file knows its own length; it's not continuous. You can't unpack part of it without changing the decompression code, there.
Cool, then it will be extremly useful in my next projects. Great!

Edit: If this is so easy, maybe Exonomizer 2.01 depacker could be a good idea. Metalbrain made a Z80 depacker for it. There are also Chrust and Bitbuster Extreme. No idea which is faster or has better compression.
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#12
Okay, the Binary manager of BorIDE will have the ability to pack binaries (also imported from TAP) using MegaLZ. It is very effective. I tried to pack a previously packed screen, where PKLite saved 1 Kb, MegaLZ saved 2 Kb. So the screen packed from 6912 Bytes using Retro-X screen compressor (which will be used in BorIDE too) to 3500 Bytes was further packed by MegaLZ to 1500 Bytes.
Code:
JP C, END_DEC40
IMHO should be replaced with
Code:
JR C, END_DEC40
because all other Jumps in the source are relative, and this saves 1 Byte and is faster (okay, nobody will notice). For me every byte counts in the Dungeon Crawler project.
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#13
What kind of information can be compressed?

Graphics, arrays, sounds..?

[Image: xaVjy.jpg]
Reply
#14
slenkar Wrote:What kind of information can be compressed?

Graphics, arrays, sounds..?

[Image: xaVjy.jpg]
Wow!
Excellent... Yes, I'm working hard to do so.

Any binary data can be compressed, but not arrays.
Natively: Graphics blocks and maps/screens (after adding map editor)
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#15
Poke 23388 with current Bank
And this is the version which can decompress from other banks to a buffer to main memory:

Code:
' MegaLZ Unpacker by Britlion, Banking by LCD SUB megaLZDepack(source as uInteger,dest as uInteger,bank as ubyte) ASM LD E,(IX+6) LD D,(IX+7) di ld a,(ix+9) ld bc,32765 out (c),a ;'Z80 depacker for megalz V4 packed files (C) fyrex^mhm ;' DESCRIPTION: ;' ;' Depacker is fully relocatable, not self-modifying, ;'it's length is 110 bytes starting from DEC40. ;'Register usage: AF,AF',BC,DE,HL. Must be CALL'ed, return is done by RET. ;'Provide extra stack location for store 2 bytes (1 word). Depacker does not ;'disable or enable interrupts, as well as could be interrupted at any time ;'(no f*cking wicked stack usage :). ;' USAGE: ;' ;' - put depacker anywhere you want, ;' - put starting address of packed block in HL, ;' - put location where you want data to be depacked in DE, ;' (much like LDIR command, but without BC) ;' - make CALL to depacker (DEC40). ;' - enjoy! ;) ;' PRECAUTIONS: ;' ;' Be very careful if packed and depacked blocks coincide somewhere in memory. ;'Here are some advices: ;' ;' 1. put packed block to the highest addresses possible. ;' Best if last byte of packed block has address #FFFF. ;' ;' 2. Leave some gap between ends of packed and depacked block. ;' For example, last byte of depacked block at #FF00, ;' last byte of packed block at #FFFF. ;' ;' 3. Place nonpackable data to the end of block. ;' ;' 4. Always check whether depacking occurs OK and neither corrupts depacked data ;' nor hangs computer. ;' ;'DEC40 LD A,80h EX AF,AF' MS: LDI M0: LD BC,2FFh M1: EX AF,AF' M1X: ADD A,A JR NZ,M2 LD A,(HL) INC HL RLA M2: RL C JR NC,M1X EX AF,AF' DJNZ X2 LD A,2 SRA C JR C,N1 INC A INC C JR Z,N2 LD BC,33Fh JR M1 X2: DJNZ X3 SRL C JR C,MS INC B JR M1 X6: ADD A,C N2: LD BC,4FFh JR M1 N1: INC C JR NZ,M4 EX AF,AF' INC B N5: RR C JP C, END_DEC40 RL B ADD A,A JR NZ,N6 LD A,(HL) INC HL RLA N6: JR NC,N5 EX AF,AF' ADD A,B LD B,6 JR M1 X3: DJNZ X4 LD A,1 JR M3 X4: DJNZ X5 INC C JR NZ,M4 LD BC,51Fh JR M1 X5: DJNZ X6 LD B,C M4: LD C,(HL) INC HL M3: DEC B PUSH HL LD L,C LD H,B ADD HL,DE LD C,A LD B,0 LDIR POP HL JR M0 END_DEC40: ld a,(23388) ld bc,32765 out (c),a ei END ASM END SUB megaLZDepack (32768,49152)
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)