heckmeck!

Nerd content and
cringe since 1999

Alexander Grupe
Losso/ATW

With Revision’s deadlines looming and the party build-up commencing today, the time budget for a possible size-coded Amiga entry doesn’t look too good anymore. Well, that’s life!

I did, however, find a little time – between my last work day before Easter and tying up my luggage – for some compression optimization. Packing before packing! :)

Specifically, I was looking to shorten the decompression header in my bootblocks. I knew I had used some magic constants before, but that was at an earlier version of Shrinkler, and maybe I haven’t used it for salvador/ZX0 at all. So let’s take a fresh look!

What exactly do the registers contain when your bootblock gets executed?

RegisterKickstart 1.2Kickstart 1.3Kickstart 2.04Kickstart 3.1
d000000000000000000000000000000809
d18000ffff8000ffff0000ffff00000808
d200000001000000010000000100000001
d300000000000000000000d6880000ad48
d400000000000000000000146800001520
d500000000000000000000000000000000
d6ffffffffffffffffffffffffffffffff
d700000000000000000000000000000000
a000001958000019580000dfb80000ed38
a100c014e600c014e20000d54c0000e2c4
a200c0185cffffffff0000d5300000e2a8
a300fe8b3a00fe86ee0000d54c0000e2c4
a4000015580000155800003e4c00002708
a500c014ba00c014b600000a4400000a74
a600c0027600c002760000146800001520
a700c014b600c014b200003e10000026cc
pc00001564000015640000dfc40000ed44

Note: Of course, this is not an exhaustive list. These are merely the values for some typical configurations: Amiga 500 with 512KB of extra RAM for Kickstart 1.2 and 1.3, Amiga 500+ for 2.04, and a vanilla Amiga 1200 for 3.1

But it seems there are some specific fixed values we can rely on across different Kickstart versions!*

*) If we only need to support classic Commodore-made AmigaOS editions, that is. This will probably not work with AROS68k or AmigaOS 3.2.x.

RegisterContents
d2Constant 00000001
d5Constant 00000000
d6Constant ffffffff
d7Constant 00000000
a1IORequest, as specified by the OS (bootblock sequence)
a6exec.library, as specified by the OS (ibid.)
pcNoteworthy: The 12 bytes before the entrypoint contain the bootblock header as it is stored on disk (i. e. 'DOS',0 followed by checksum and rootblock longwords

Nifty! Now let’s delete some code. With Shrinkler, we can save four bytes in the initialization code:

ShrinklerDecompress:
        ; Init range decoder state
        moveq   #0,d2           ; omit, use d5 instead
        moveq   #1,d3           ; omit, use d2 instead
        ...

And two bytes for ZX0:

zx0_decompress:
        moveq   #-128,d1        ; initialize empty bit queue
        moveq   #-1,d2          ; omit, use d6 instead
        ...

I love that each of the values 0, 1, and -1 is of use somewhere!

For both packers, the bootblock starts like this:

disk:   dc.b    'DOS',0
        dc.l    0               ; checksum gets inserted here
root:   dc.l    $20000          ; destination; usually 880=rootblock 
entry:  move.l  root(pc),aX     ; destination address
        lea     meat(pc),aY     ; start of compressed data
        pea     (aX)            ; rts will jump into unpacked code
        ...                     ; decompression code starts here

With this, my current bootblock stubs take up this much space:

CompressionStub sizeRoom for compressed data
Shrinkler168856
Shrinkler, parity disabled162862
Savlador/ZX0100924

Note: It pays out to have build scripts ready for all compression schemes – with my current work-in-progress payload, the “winner” (in terms of best overall compression) fluctuates constantly!

Now, either I find some more bytes to spare during the party or I put some of that saved space to good use with an entry! :)

Then again, I already have my working gloves on…

previous next close