IK+ Turbo

IK+ Turbo

Roudoudou a récemment produit une version ‘Turbo’ du jeu International Karaté Plus, qui, comme son nom l’indique, est une version plus rapide du jeu, grâce à quelques optimisations qu’il a pu apporter dans le code. Retour sur les modifications apportées.

Pour commencer, le code du jeu, sommairement désassemblé, est disponible sur rasmlive. Les modifications peuvent être appliquées grâce aux symboles suivants:

OPTIM_CLEAR  EQU 2 ; Optimisation de l'effacement de l'écran
OPTIM_SHADOW EQU 1 ; Optimisation du dessin des ombres
OPTIM_ROUD   EQU (OPTIM_CLEAR |OPTIM_SHADOW)

Optimisation de l’effacement de l’écran

C’est la l’essentiel du gain de temps que l’on obtient. En effet, a chaque trame, l’intégralité de la zone de l’écran ou se situent les personnage est effacée, en remplissant la zone en question de gris, qui fait 8 bloc de 8 lignes, pour une largeur d’écran de 64 octets (CRTC.R1=32). il s’agit d’écrire 8*8*64 = 4096 octets. L’affichage est géré par un double buffer, donc l’adresse destination est calculée a chaque fois de la facon suivante:

ld hl,#0340
; Current Buffer #80 or #c0
ld a,(curScreenAdr)
or h
ld h,a

Ensuite, l’effacement se fait via une boucle répétée 8 fois, d’appels a une routine d’effacement, qui utilise LDI pour dupliquer une valeur (0 en l’occurence) sur toute la zone concernée:

  ld a,8
loop: 
  push af
,hl
  push hl
  ld d,h
                   ;  DE = HL+1
  ld e,l
  inc e
  ld (hl),0                ; Motif
  repeat 7                 ; Duplique 64*7+63 = 255 octets 
    call clearLine64
  rend
  call clearLine63
  pop hl
  ld a,h                    ; Passe a la ligne suivante
  add a,8
  ld h,a
  pop af
  dec a
  jr nz,loop

La routine clearLine étant simplement une suite de 64 LDI (avec un point d’entrée permettant de faire 63 recopies)

clearLine64:
  ; Effectue 64 recopies
  ldi
clearLine63:
  ; Effectue 63 recopies
  repeat 63
    ldi
  rend
ret
Optimisation

Clairement, ici, il est possible d’utiliser la pile pour remplir la zone mémoire en question. Le seul souci avec cette technique est qu’il faut faire attention à ce qu’il n’y ait pas de conflit avec les interruptions.

ld hl,#0600
ld a,(curScreenAdr)
 ; Current Buffer #80 or #c0
or h
ld h,a

ld c,8
                       
.loop1:
  ld de,0
                    ; Motif
  push hl
  di
                         ; Bloque les interruptions
  ld (.store_sp+1),sp
        ; Sauvegarde SP
  ld sp,hl
                   ; SP = HL = Destination
  ld b,#15
  ld a,2
.loop0:
  repeat 16
                  ; Ecrit 32 octets      
    push de
                   
  rend
  djnz .loop0
  ld b,a
  dec a
  djnz .loop0
.store_sp:
                    ; Restitue SP
  ld sp,0
                     
  ei
                          ; Retablit les interruptions
  pop hl
  ld a,h
                      ; Ligne suivante
  add 8
  ld h,a
  dec c
  jr nz, .loop1

Optimisation du dessin des ombres

Le dessin des ombres est aussi une routine assez gourmande qui consiste a recopier des octets en mémoire, sur une bande de 16 lignes. Ce code est répété 8 fois, pour chaque début de ligne en mémoire vidéo:

  ld a,64
  ld b,2
loop: ex af,af'
  ld c,(hl)
  ld a,(bc)
  ld (de),a
  inc hl
  inc de
  ex af,af'
  dec a
  jr nz, loop
Routine rapide

L’optimisation consiste essentiellement à dérouler la boucle. Ici au lieu de 64 sauts, on en fait plus que deux. De plus les incréments des registres hl et de sont remplacés par des incréments de l et e, car les adresses en questions sont toujours alignées de facon a ce qu’il n’y ait jamais de débordement.. On gagne ainsi 8*(60*3 + 64*2) nops, soit environ 40 raster lines.

ld a,2
ld b,2
.loop:
  ex af,af'
  repeat 32
         ; Dérouler la boucle 
    ld c,(hl)
    ld a,(bc)
    ld (de),a
    inc l
           ; Incrément L au lieu de HL
    inc e
           ; Incrément E au lieu de DE
  rend
  ex af,af'
  dec a
  jp nz, .loop
      ; Comme on a déroulé, on est trop loin pour faire un saut relatif

Il existe probablement d’autres endroits ou le code pourrait être optimisé. L’affichage du décor par exemple. Mais ces deux optimisations permettent déjà de gagner énormément de CPU, et d’augmenter très clairement le framerate du jeu.

Les versions optimisées présentées ici pourraient l’être encore plus, par exemple en déroulant les boucles complètement, et éviter des sauts inutiles et la sauvegarde de registres, mais elles ont été faites ainsi pour que le code optimisé ne prenne pas plus de place en mémoire, et donc puisse loger a la place du code original.

Liens