À l'image des modifications de ROM proposées par Krakowicz (grand cracker US) ou Lot (pour sa Kracrom spéciale Godfather), incorporer une option de sauvegarde de certaines pages mémoire lors d'un RESET Custom, est une évidence pour tout bidouilleur un peu curieux de nature. Sauvegarder, par exemple, les pages 0 à 8 pour examen ultérieur, serait une bonne idée...

Pourquoi cette partie en particulier ? Tout simplement parce que ces pages mémoire sont des zones clés de l'Apple II. Pour rappel :

  • La page 0, utilisée par de nombreuses routines en ROM, est modifiée en permanence. Et de par les spécificités du 6502 (avec ses instructions dédiées), c'est une page particulièrement utilisée par les programmes.
  • La page 1 contient la pile. Elle aussi change constamment au gré de l'exécution d'un programme.
  • La page 2 correspond au buffer d'entrée. Le moindre appui sur une touche altère son contenu.
  • La page 3, outre le fait de contenir plusieurs vecteurs intéressants, se trouve surtout au mauvais endroit : elle sera donc sauvée avec le reste (oui c'est super technique...).
  • Les pages 4 à 7 correspondent aux adresses de l'écran TEXT, Page 1. Là par contre le moindre défilement vertical d'une ligne suffira à totalement modifier le contenu des 4 pages. À préserver donc !
  • La page 8, elle, sera écrasée par le simple boot d'une disquette Dos. Autant en profiter pour la déplacer elle aussi.

Rien que l'appel au Monitor modifiera, au moins en partie, chacune de ces pages. On comprendra aisément que ce sont des endroits privilégiés pour y cacher des routines que l'on veut garder secrètes. D'où l’intérêt de pouvoir examiner ces pages et donc de les sauvegarder avant le saut au Monitor.

Le meilleur endroit pour déplacer ces zones mémoire, se situe au niveau de la page Hires 1. Essentiellement utilisée pour des images, on peut donc y loger provisoirement nos pages. L'essentiel étant de pouvoir les examiner à loisir sans perte de données après avoir récupéré la main.

Seul problème : une routine de déplacement, même très simple, prend de la place, il va donc falloir la loger quelque part. Sur IIe (et II+), la solution la plus évidente est de remplacer les routines Monitor WRITE et READ, utilisées par les commandes basic LOAD et SAVE. Attention, ne pas confondre avec les commandes DOS. Ici, on parle bien des deux commandes permettant de sauver vers, et de relire depuis, un magnétophone à cassette. Avec l'utilisation du DISK II, ces deux routines ne sont plus utilisées et laissent donc de la place pour y loger notre propre routine.
Sur IIe Enhanced, ces deux routines existent toujours. Toutefois, ce ne sont plus du tout les mêmes et il y a beaucoup moins de place disponible. Voilà pourquoi cette routine ne s'adresse qu'au IIe UnEnhanced (ou II+). Sur IIe Enhanced, il faudra trouver une autre place...

  FA85- AD F2 03      LDA   $03F2   ; test vecteur reset        
  FA88- D0 0C         BNE   $FA96   ; non nul ?                 
  FA8A- AD F3 03      LDA   $03F3   ; idem                      
  FA8D- D0 07         BNE   $FA96   ;                           
  FA8F- AD F4 03      LDA   $03F4   ; test octet contrôle       
  FA92- C9 FF         CMP   #$FF    ; égal à #$FF ?             
  FA94- F0 10         BEQ   $FAA6   ; oui ? alors go COLDSTART !
 
  FA96- 4C 1D FD      JMP   $FF1D   ; saut vers routine évoluée !
 
  FA99- 00 00                       ; octets inutilisés (mis à 00) 
  FA9B- A0 03         LDY   #$03    ; routine originale
  FA9D- 8C F2 03      STY   $03F2   ; que l'on conserve car
  FAA0- 4C 00 E0      JMP   $E000   ; utilisée par la modif Autostart
  FAA3- 4C 59 FF      JMP   $FF59   ; saut monitor !

La première partie de la routine est la même que pour le RESET simple. Seul le saut en $FA96 ne s'effectue plus vers $FAA3 mais vers $FF1D. Tout le reste est identique. On conserve donc l'Autostart (modifié ou pas) en cas de COLDSTART. Et on s'oriente vers notre routine perso en cas de RESET/WARMSTART.

  FECD-	  60	      RTS           ; neutralisation SAVE
  FECE-   AD 00 C0    LDA   $C000   ; attente
  FED1-   10 FB       BPL   $FECE   ; de l'appui d'une touche
  FED3-   8D 10 C0    STA   $C010   ; réinitialise clavier
  FED6-   C9 C4       CMP   #$C4    ; touche "D" (Dump) ?
  FED8-   D0 38       BNE   $FF12   ; non ?
  FEDA-   A0 00       LDY   #$00    ; oui
  FEDC-   B9 00 00    LDA   $0000,Y ; on commence
  FEDF-   99 00 20    STA   $2000,Y ; par mover toute la page 0
  FEE2-   C8          INY
  FEE3-   D0 F7       BNE   $FEDC
  FEE5-   84 00       STY   $00     ; afin d'utiliser
  FEE7-   84 02       STY   $02     ; ensuite les octets
  FEE9-   A9 01       LDA   #$01    ; page 0
  FEEB-   85 03       STA   $03     ; pour un déplacement
  FEED-   A9 21       LDA   #$21    ; indexé
  FEEF-   85 01       STA   $01     ; $0100 -> $2100
  FEF1-	  D0 0B	      BNE   $FEFE   ; saut inconditionnel ici
  FEF3-   4C A6 FA    JMP   $FAA6   ; COLDSTART                   
 
  FEF6-   20 00 FE    JSR   $FE00   ; ne pas toucher
  FEF9-   68          PLA   	    ; à cette partie
  FEFA-   68          PLA           ; sous peine
  FEFB-   D0 6C       BNE   $FF69   ; de gros problèmes  
 
  FEFD-	  60          RTS           ; neutralisation LOAD
  FEFE-   B1 02       LDA   ($02),Y ; on déplace de $0100+
  FF00-   91 00       STA   ($00),Y ; vers $2100+
  FF02-   C8          INY
  FF03-   D0 F9       BNE   $FEFE
  FF05-   E6 01       INC   $01
  FF07-   E6 03       INC   $03
  FF09-   A5 03       LDA   $03
  FF0B-   C9 09       CMP   #$09    ; est-ce la page 9
  FF0D-   D0 EF       BNE   $FEFE   ; non ? on boucle
  FF0F-   4C 59 FF    JMP   $FF59   ; saut monitor !
  FF12-   C9 CD       CMP   #$CD    ; est-ce la touche "M" (move) ?
  FF14-   F0 F9       BEQ   $FF0F   ; si oui saut direct au monitor
  FF16-   C9 D2       CMP   #$D2    ; est-ce la touche "R" (reboot) ?
  FF18-   F0 D9       BEQ   $FEF3   ; si oui saut vers le COLDSTART
  FF1A-   6C F2 03    JMP   ($03F2) ; toutes les autres touches envoient
                                    ; vers le vector Reset par défaut
 
  FF1D-   A0 30	      LDY #$30      ; petit son
  FF1F-   A9 20       LDA #$20      ; pour le fun et
  FF21-   20 A8 FC    JSR $FCA8     ; surtout pour avertir
  FF24-	  AD 30 C0    LDA $C030	    ; l'utilisateur qu'il
  FF27-   88          DEY           ; va falloir appuyer
  FF28-   D0 F5       BNE           ; sur une touche !
  FF2A-   4C CE FE    JMP $FECE     ; saut au début de la routine

La seconde partie de la routine demande quelques éclaircissements  :

  • $FECD et $FEFD sont les deux points d'entrées des routines WRITE et READ que l'on écrase. Pour éviter que les commandes LOAD et SAVE qui les utilisent ne plantent lamentablement, j'ai donc mis deux RTS pour les neutraliser.
  • entre les routines WRITE ($FECD-$FEF5) et READ ($FEFD-$FF2C), il y a une zone à ne surtout pas écraser par notre code : $FEF6-FEFC (sous peine de gros problèmes). On passe donc par-dessus à l'aide d'un saut.
  • en $FEDC, j'utilise un LDA $0000,Y (absolu, Y) et non pas un LDA $00,X (page 0, x).Les deux instructions utilisent le même nombre de cycles. Le LDA absolu est certes plus long d'un octet mais cet octet me sert justement à retomber sur mes pieds quand il faudra passer par-dessus la zone intouchable dont je parle juste au-dessus.
  • pour atteindre le COLDSTART, on passe par un saut intermédiaire. Je ne pouvais faire un branchement direct par BEQ depuis $FF14  vers $FAA6 (déplacement trop important). Comme j'avais de la place avant la zone intouchable, j'ai déporté le JMP à cet endroit.
  • la routine READ se termine officiellement en $FF3A. Toutefois la partie en $FF2D (qui affiche le message "ERR" suivi d'un joli BiP) est utilisée régulièrement pour signaler une erreur par des programmes tiers. Ne pas y toucher donc !

 

Sinon, au fait, elle fait quoi exactement cette routine ?

Et bien, suite à un Reset donc, après un petit "bip" (custom lui aussi), elle attend que l'on appuie sur une touche. Plusieurs choix possibles :

  • touche "M" (pour Monitor) : nous envoie directement sous Monitor.
  • touche "R" (pour Reboot) : nous envoie directement vers le COLDSTART et force donc un recheck des Slots par l'Autostart pour un reboot en bonne et due forme.
  • touche "D" (pour Dump) : copie les pages 0 à 8 (inclues) vers l'espace $2000-$28FF et saute ensuite au Monitor.
  • toute autre touche effectuera un saut vers le contenu du vecteur Reset. L'idée ici est d’effectuer ce que le programme avait prévu à la base en cas de RESET, comme par exemple revenir à un menu ou autre. J'attire toutefois votre attention sur les programmes qui s'amusent à corrompre uniquement l'octet de contrôle du vecteur Reset ($3F4) pour forcer un COLDSTART. Ils risquent ici de poser problème. En effet, vu qu'il n'y aura pas de COLDSTART effectué (ce qui est le but premier de la modification...) mais un saut vers le contenu du vecteur Reset, si celui-ci ne contient pas une adresse valide, plantage assuré. Forcez dans ce cas manuellement le saut au Monitor par "M" ou le reboot par "R".

 

Où effectuer les modifications  ?

  • à partir des offsets $1A85 pour la première partie et $1ECD pour la seconde dans une ROM de IIe UnEnhanced. Je rappelle que cette modification est non compatible avec la ROM IIe Enhanced !
  • à partir des offsets $285 et $6CD pour un fichier F8.rom type AppleWin.