Shrinkler sur CPC!

Roudoudou a récemment réalisé le portage de la routine de décompression de « Shrinkler », un compresseur très performant,  sur Z80. Il explique lui même sur Memoryfull les détails de ce portage, et propose une comparaison avec les autres crunchers.

Shrinkler fait partie de la famille des crunchers  qui offrent un niveau de compression très élevé, mais au prix d’un temps de décompression important (environ 5 secondes par kilo-octet de données crunchées). Il faut donc l’utiliser à bon escient! De plus, il a été conçu pour optimiser le code assembleur des processeurs de la famille des 68000. Il n’est utilisable sur CPC qu’en mode ‘data’. Ceci étant dit, c’est donc un outil idéal pour vos futures productions 4KB!

Je vous propose ici un rapide tuto, avec rasm (c’est donc un article très roudoudou-compatible!), dans lequel on va tester la routine de décompession de shrinkler sur CPC! Nous allons compresser une image, ce qui n’est pas forcément le bon usage, mais comme cela ce sera bien visuel. On pourra en particulier constater que la décompression prend un peu de temps… On va donc partir d’un ficher de 16KO a compresser. avec comme adresse de départ #C000, l’adresse de la mémoire vidéo par défaut sur CPC.

Compression

La routine peut être trouvée ici. L’archive contient le fichier original de Roudoudou, mais aussi des version optimisées, dont celle de Madram.

Commençons tout d’abord par compresser le fichier. Ca se passe sur PC, par exemple sous linux ou windows, avec une commande de la sorte (merci Tronic pour m’avoir indiqué les options d’optimistion supplémentaires!) :

shrinkler -d -p -9 inputfile.bin crunched.bin
  • -d pour le mode data
  • -9 pour augmenter le niveau de compression au maximum

Pour l’exemple, j’ai utilisé le splash screen de Ghost’n’Goblins, qui passe de 16Kb à 8672 octets, une fois compressé.

Décompression

include "../lib/toolbox.asm"

DESTINATION: EQU #C000
ENTRY_POINT: EQU #BB06

; Si ROUDOUDOU = 1 la version originale de Roudoudou est utilisée
; Sinon C'est la version optimisée par Madram qui est utilisée
ROUDOUDOU: EQU 1

ORG #4000   
        ; Saut optionnel si on veut que le point d'entrée soit #4000               
        ; (Et qu'on a 3 octets à perdre)
        JP START
        
CRUNCH_DATA:
        INCBIN "crunched.bin"
START:  
        ; Desactive ITs et Sauvegarde des registres Mirroir
        DI
        DISABLE_INT (inter+1)
        PUSH_MIRROR_REGS
        EI
        
        ; Décompression        
        LD      IX,CRUNCH_DATA
if ROUDOUDOU==1
        LD      HL,DESTINATION
else
        LD      DE,DESTINATION
endif
        call shrinkler_decrunch
        
        ; Restauration registres et ITs     
        POP_MIRROR_REGS     
inter   LD      HL,0 
        LD      (#38),HL    
        ; Appel du programme décompressé (si existant)
        CALL    ENTRY_POINT
        ; On peut aussi restaurer les registres et ITs ici
        ; Suivant ce que fait le point d'entrée
        RET        

Les macros pour sauvegarder/restaurer les registres mirroirs sont dans le fichier ‘toolbox.asm’, dont voici le contenu:

; Desactive les interruptions                                       
MACRO DISABLE_INT store
    DI 
    LD      HL,(#38) 
    LD      ({store}),HL 
    LD      HL,#c9fb    ; EI + RET
    LD      (#38),HL 
    EI 
MEND

; Sauvegarde les registres mirroir
MACRO PUSH_MIRROR_REGS
    di
    exx
    push hl
    push bc
    push de
    exx
    ex AF,AF'
    PUSH AF
    ex AF,AF'
    ei
MEND

; Restaure les registres mirroir
MACRO POP_MIRROR_REGS
    di
    ex AF,AF'
    POP AF
    ex AF,AF'   
    exx
    pop de
    pop bc
    pop hl
    exx
    ei
MEND

Maintenant si l’on recommence l’opération, mais en visualisant la mémoire qui commence à l’adresse #4000

out &bc00,&0c 
out &bd00,&10

Fantaisie en passant

Maintenant que la fine fleure des CPCistes a optimisé au maximum le code de décompression, il est temps d’y ajouter notre grain de sel, d’alourdir leur code, mais pour une bonne cause: en effet, attendre une quinzaine de secondes sans qu’il ne se passe rien à l’écran est passablement long et ennuyeux. Au prix de quelque octets et d’un léger ralentissement, il est possible d’agrémenter ce moment d’une animation minimaliste, qui détournera le spectateur de son impatience maladive.

Dans la routine de décompression, la boucle qui a pour label ‘literal’ est appelée quelques fois par trame vidéo. On peut y insérer son propre code a ce niveau, en prenant bien soin de sauvegarder les registres que l’on va utiliser. On pourrait écrire dans la mémoire vidéo (faire une barre de progression par exemple), mais en l’occurrence comme on décompresse une image, on va se contenter de changer les couleurs du bords:

literal                                                         
            PUSH    AF
            PUSH    HL
            PUSH    BC
            LD      A,C         
            LD      BC,GA_PORT | GA_SELECT_BORDER
            OUT     (C),C
            AND     31
            OR      GA_SET_COLOR+1
            OUT     (C),A
            POP BC
            POP HL
            POP AF

Pas de commentaire particulier sur ce bout de code, si ce n’est que la valeur du registre C est utilisée pour décider de la couleur. Cela évite d’utiliser par exemple le registre R pour obtenir une couleur pseudo aléatoire. Par ailleurs, quelques symboles sont utilisés:

GA_PORT:           EQU #7F00
GA_SELECT_BORDER:  EQU #10
GA_SET_COLOR:      EQU #40

Dans la version ‘madram’ on pourrait aussi utiler H ou IXL au lieu de C pour avoir une couleur qui change de facon moins aléatoire.

Liens