Table des matières

Retourner au sommaire

Test CRTC

Les yeux dans les yeux, dis-moi qui tu es ! Vous n'êtes pas sans savoir qu'au fil des années, les CPC ont été distribués avec diverses révisions du CRTC. En usage nominal cela serait sans doute passé totalement inaperçu, mais comme les CPCistes aiment bien titiller leur machine, on s'est rapidement retrouvé contronté à des problèmes de compatibilité CRTC !

“Horreur et damnatation ! Comment faire pour que mes routines hightech fonctionnent partout”, s'exclame le petit blond à lunette. “Gros malin”, lui répond alors le lapin rose, “il suffit de faire un test CRTC !”

Vous trouverez donc dans cette section diverses manières d'identifier les CRTC avec les explications qui vont bien.

Les différents types de CRTC

Basé sur les articles publiés dans Quasar CPC numéro 11, Perfectionnement à l'Assembleur, et numéros 12 et 21, Assembleur : Coding, par OffseT.

Remis en forme et enrichi par Pulkomandy à partir d'informations issues d'Amslive numéros 16, 18 et 19 (articles de Madram) et du Grimware.

Les types connus

À rédiger et à détailler.

Les différences connues

Rajouter une petite introduction.

Type 0 1 2 3 4
Ports &BExx et &BFxx
Lecture des registres 12 and 13 sur le port &BFxx Oui Non8) Non9) Oui Oui
Décodage complet du numéro de registre sur le port &BFxx Oui10) Oui Oui Non11) Non
Lecture du registre 31 sur le port &BFxx 0 Hi-Z12) 0 Registre 15 Registre 15
Lecture de l'état de la VBL sur le bit 5 du registre 10 sur le port &BFxx Non Non Non Oui Oui
Lecture du compteur de bloc sur le registre 11 sur le port &BFxx Non Non Non Oui Oui
Registre de status accessible sur le port &BExx (VBL, border) Non13) Oui Non 14) Non15) Non16)
Registres
R1 > R0 inhibe le border Non Oui Non Oui Oui
R2 + R3 > R0 Décale l'écran17) Décale l'écran18) Pas de VBL Décale l'écran19) Décale l'écran20)
R2 + R3 = R0 Ok Ok Pas de VBL Décale l'écran21) Décale l'écran22)
Le bit 7 du registre 3 change la durée de la VBL Oui23) Non24) Non Oui25) Oui26)
R6 = 0 crée des artéfacts à l'écran Oui27) Non28) Oui29) Non Non
Le registre 8 permet de passer en mode entrelacé (bits 0 et 1) Buggé30) Correctement31) Directement Buggé32) Buggé33)
Le registre 8 permet de décaler et de désactiver le border (bits 4 et 5) Oui Non Non Oui Oui
Astuces de demomakers
Activation du split-border Avec le registre 834) Avec le registre 635) Impossible Avec le registre 836) Avec le registre 837)
Validation de l'offset après reprogrammation des registres 12 et 13 À l'écran suivant Immédiatement38) À l'écran suivant À l'écran suivant À l'écran suivant
Validation des registres 9 et 4 après reprogrammation Bufférisés Immédiatement39) Bufférisés Bufférisés Bufférisés
Rupture ligne-à-ligne possible (R9 = R4 =0 ) Oui Oui Non Oui Oui
Valeur minimale du registre 0 1 0 040) 0 0
Particularités du PPI41)
Programmer le PPI remet à 0 la valeur du port de donnée Oui Oui Oui Non42) Oui
Le port B du PPI peut être utilisé en sortie Non Non Non Oui Non

Les méthodes de détection

Le Test CRTC "de base"

Basé sur l'article publié dans Quasar CPC numéro 12, Assembleur : Coding, par OffseT.

À saisir…

Le Test CRTC "même pas mal"

Basé sur l'article publié dans Quasar CPC numéro 21, Assembleur : Coding, par OffseT.

Il y a quelques temps de cela, Targhan, m'avait demandé de lui fournir un test CRTC “neutre” pour la non moins célèbre Demo Iz Art. Ce test CRTC devait avoir pour particularité d'indentifier le CPC sans modifier les registres du CRTC (pas de saut d'écran, etc.). L'exercice étant assez ludique, après avoir réalisé ce petit programme afin que notre barbare puisse l'intégrer à la DIA, j'ai continué d'enrichir ce test d'une multitude de méthodes de détection diverses et variées. Ce code regroupant au final pas mal de petites choses fort sympathiques, nous avons décidé de le publier afin que tout le monde puisse en profiter.

Qu'est-ce que ça fait ?

Je devinerai tout sur toi juste en te regardant ! Je ne vais pas vous détailler ici le fonctionnement du code car vous constaterez que le listing qui suit est largement commenté et, qu'avec un minimum d'efforts, vous parviendrez à le comprendre. Sachez juste que le test utilise plusieurs routines lancées consécutivement, chacune permettant d'identifier tel ou tel type de CRTC. Il y a de nombreuses redondances et toutes les routines ne sont absolument pas indispensables pour détecter avec certitude un type de CPC. Libre à vous d'utiliser celles qui vous paraissent les plus élégantes ou toutes si vous êtes un peu paranoïaque.

Notez également qu'il s'agit d'un test destiné à être lisible et il n'est pas particulièrement optimisé. Toutefois, il fait ce qu'il faut comme il faut. Libre à vous là aussi de maquiller ou même d'intégrer carrément les routines à votre code plutôt que d'avoir un test “à part”. Absolument aucun des tests publiés ici ne modifient le CRTC ou le Gate Array ; de ce fait, l'affichage n'est pas altéré durant la détection. Seul l'état de configuration du PPI est altéré par quelques tests. Le résultat cumulé des divers test permet non seulement d'identifier avec certitude un CRTC mais aussi de disqualifier tout CPC ayant donné des résultats incohérents d'un test à l'autre (ce qui sera le cas des CPC en panne, des CRTC non connus à ce jour et, accessoirement, des émulateurs).

Qu'est-ce qu'on teste ?

Nous avons plusieurs types de tests. En premier lieu, nous avons ceux qui testent les lectures sur les registres du CRTC. Plusieurs registres, selon qu'ils soient accessibles en lecture ou pas, vont nous permettre de différencier divers CRTC (lecture de l'offset sur les registres 12 et 13, lecture de la dernière ligne de VBL sur le registre 10, lecture du bloc en cours de balayage sur le registre 11). On peut également vérifier comment se comporte la lecture sur les registres qui sont sensés ne rien renvoyer. Les valeurs renvoyées d'un type de CRTC à un autre étant différentes, on peut là aussi en tirer des conclusions intéressantes. Enfin, on va lire le port de statut du CRTC (&BExx) qui nous permet par exemple de détecter le border uniquement sur CRTC type 1.

En complément de ces tests directement liés au CRTC, nous avons quelques tests qui scrutent le fonctionnement du PPI. En effet, sur CPC+, le PPI est émulé et a quelques différences de fonctionnement notables par rapport à son modèle (phase d'init, programmation I/O).

Pour chaque test, ce qu'il fait et ses conditions de bon fonctionnement sont décrites dans le listing.

Qu'est-ce qu'on fait là ?

Il ne s'agit pas d'un test exhaustif, en effet, tous ces tests ont pour particularité d'être neutres ; ils ne modifient pas la programmation du CRTC et donc rien ne “saute” ou ne change de couleur à l'écran. Si on décide de se dispenser de cette contrainte, il est possible d'enrichir encore ce programme d'autres routines de test (test du mode entrelacé, test de l'overflow du registre 2, test du mode IM 2, etc.). Toutefois, il s'agit d'une bonne base de départ qui, je le pense, vous permettra de découvrir des bits de test encore méconnus de nos chers CRTC.

Listing : Test CRTC neutre

Télécharger le listing au format Maxam 1.5

; Test CRTC version 3.0
; (12/01/2005) par OffseT (Futurs')
 
        Nolist
 
; Réalisé entièrement sur un véritable CPC
; Plus aucun registre du CRTC n'est modifé durant les tests !
 
; L'historique...
 
; Test CRTC version 1.1
;   - Test originel (23.02.1992) par Longshot (Logon System)
;   ce test CRTC est celui crée par Longhost et utilisé dans la
;   plupart des démos du Logon System.
 
; Test CRTC version 1.2
;   - Amélioration de la détection Asic (02/08/1993) par OffseT
;   le test basé sur la détection de la page I/O Asic qui
;   imposait de délocker l'Asic a été remplacé par un test
;   des vecteurs d'interruption (mode IM 2). Le délockage de
;   l'Asic n'est plus nécessaire.
;   bug connu ; ce test ne fonctionne pas nécessairement sur un
;   CPC customisé (notamment avec une interface gérant les
;   interruptions en mode vectorisé) ou sur un CPC+ dont le registre
;   Asic IVR a préalablement été modifié.
;   - Correction du bug de détection CRTC 1 (18/06/1996) par OffseT
;   sous certaines conditions de lancement le CRTC 1 était détecté
;   comme étant un CRTC 0 (on peut constater ce bug dans The Demo
;   et S&KOH). La méthode de synchronisation pour le test de détection
;   VBL a été fiabilisée et ce problème ne devrait plus survenir.
 
; - Test CRTC version 2.0
;   - Ajout d'un test émulateur (03/01/1997) par OffseT
;   ce test est basé sur la détection d'une VBL médiane lors de
;   l'activation du mode entrelacé. Les émulateurs n'émulent pas
;   cette VBL.
;   limitation systématique ; ce test ne permet pas de distinguer
;   un véritable CRTC 2 d'un CRTC 2 émulé.
 
; - Test CRTC version 3.0
;   - Retrait du test émulateur (20/12/2004) par OffseT
;   ce test ne représente aucun intéret réel et a le désavantage
;   de provoquer une VBL parasite pendant une frame.
;   - Remplacement du test Asic (29/12/2004) par OffseT
;   le nouveau test est basé sur la détection du bug de validation
;   dans le PPI émulé par l'Asic plutôt que sur les interruptions
;   en mode IM 2. C'est beaucoup plus fiable puisque ça ne dépend
;   plus du tout de l'état du registre IVR ni des extensions gérant
;   les interruptions connectées sur le CPC. Merci à Ram7 pour  l'astuce.
;   Limitation systématique ; l'état courant de configuration des ports
;   du PPI est perdue, mais ça ne pose normalement aucun problème.
;   - Remplacement du test CRTC 1 et 2 (29/12/2004) par OffseT
;   le test originel de Longshot était basé sur l'inhibition de
;   la VBL sur type 2 lorsque Reg2+Reg3>Reg0+1. Ce test modifiait
;   les réglages CRTC et l'écran sautait pendant une frame. Il a été
;   remplacé par un test basé sur la détection du balayage du border
;   spécifique au type 1 qui n'a pas ces inconvénients.
;   bug connu (rarissime) ; ce test renvoie un résultat erroné sur
;   CRTC 1 si reg6=0 ou reg6>reg4+1... ce qui est fort improbable.
;   - Modification du test CRTC 3 et 4 (29/12/2004) par OffseT
;   le test ne modifie plus la valeur du registre 12. Toutefois
;   il en teste la cohérence et vérifie également le registre 13.
;   limitation (rare) ; ce test ne fonctionne pas si reg12=reg13=0.
;   - Réorganisation générale des tests (29/12/2004) par OffseT
;   chaque test est désormais un module qui permet, par le biais
;   d'un système de masques de tests, de différencier les CRTC au
;   fur et à mesure.
;   - Retrait des dépendances d'interruption (29/12/2004) par OffseT
;   plus aucun test ne fait usage des interruptions pour se synchroniser.
;   - Ajout d'un test de lecture du port &BFxx (29/12/2004) par OffseT
;   ce test permet de différencier les CRTC 1 et 2 des autres et vient
;   en complément du test (historique) sur le timing VBL.
;   limitation (rare) ; ce test ne fonctionne pas si reg12=re13=0.
;   - Ajout d'un test de lecture des registres 4 et 5 (30/12/2004) par OffseT
;   ce test donne théoriquement les mêmes résultats que le test
;   initial de détection 3 et 4 basé sur des lectures sur le port
;   &BExx ; il consiste à lire les registres 12 et 13 via leur miroir
;   sur l'adressage des registres 4 et 5 sur type 3 et 4.
;   limitation (rare) ; ce test ne fonctionne pas si reg12=reg13=0.
;   - Ajout d'un test de lectures CRTC illégales (12/01/2005) par OffseT
;   ce test vérifie qu'on obtient bien la valeur 0 en retour
;   lors d'une tentative de lecture illégale d'un registre du
;   CRTC en écriture seule. Ceci permet de différencier les types
;   0, 1 et 2 des types 3 et 4.
;   - Ajout d'un test du port B du PPI (12/01/2005) par OffseT
;   ce test vérifie si le port B peut-etre configuré en sortie.
;   Ceci permet d'identifier le type 3.
;   Limitation systématique ; l'état courant de configuration des ports
;   du PPI est perdue, mais ça ne pose normalement aucun problème.
;   - Ajout d'un test de détection de fin de VBL (12/01/2005) par OffseT
;   ce test vérifie que le bit 5 du registre 10 du CRTC permet bien
;   de détecter la dernière ligne de VBL sur les CRTC 3 et 4. Ceci
;   permet de différencier les types 0, 1 et 2 des types 3 et 4.
;   bug systématique ; si le bit 7 du registre 3 est à zéro (double VBL)
;   le test renvoie un mauvais résultat.
;   - Ajout d'un test de lecture du registre 31 (12/01/2005) par OffseT
;   ce test vérifie sur la valeur en lecture renvoyée pour ce registre
;   est non nulle. Si c'est le cas ça veut dire qu'on a lu soit un état
;   de haute impédance (cas du type 1) soit le registre 15 qui était non
;   nul (cas des types 3 et 4). On peut alors conclure que l'on a ni un
;   type 0, ni un type 2. Si la valeur est nulle on ne peut rien conclure
;   et le test est inopérant. 
;   limitation rarissime ; ce test ne fournit pas de résultat sur type 1
;   si l'état de haute impédance est altéré
;   limitation courante ; ce test ne fournit pas de résultat sur types 3 et 4
;   si le registre 15 est nul (ce qui est la valeur par défaut)
;   - Ajout d'un test de détection des blocs 0 et 1 (12/01/2005) par OffseT
;   ce test vérifie que la détection des blocs 0 et 1 est fonctionnelle
;   sur les types 3 et 4 à l'aide des flags du registre 11 du CRTC. Ceci
;   permet de différencier les types 0,1,2 des 3,4.
;   limitation systématique ; le registre 9 doit valoir 7 sinon le
;   résultat est faux.
 
; Note ; une limitation décrit un cas dans lequel le test ne renvoie
; aucun résultat (il ne parvient pas à distinguer les CRTC) alors qu'un
; bug connu décrit un cas dans lequel le test peut renvoyer une mauvaise
; réponse (ce qui est beaucoup plus grave !).
 
; Les différents types de CRTC connus...
 
; 0 ; 6845SP                ; sur la plupart des CPC6128 sortis entre 85 et 87
; 1 ; 6845R                 ; sur la plupart des CPC6128 sortis entre 88 et 89
; 2 ; 6845S                 ; sur la plupart des CPC464 et CPC664
; 3 ; Emulé (CPC+)          ; sur les 464 plus et 6128 plus
; 4 ; Emulé (CPC old)       ; sur la plupart des CPC6128 sortis en 89 et 90.
 
 
; Le programme qui utilise le test CRTC...
 
        Org &9000
 
        call testcrtc   ; On lance le test CRTC !
 
        add a,48        ; On affiche le type de CRTC
        call &bb5a
 
        ret             ; On rend la main
 
; Le test CRTC...
 
; Attention ! Le CRTC doit être dans une configuration
; rationnelle pour que les tests fonctionnent (VBL et
; HBL présentes, registres 6 et 1 non nuls, bit 7 du
; registre 3 non nul, etc.)
 
; En sortie A contient le type de CRTC (0 à 4)
; A peut valoir &F si le CRTC n'est pas reconnu
; (mauvais émulateur CPC ou mauvaise configuration
; CRTC au lancement du test)
 
TestCRTC
        ld a,&ff
        ld (typecrtc),a
        di                      ; CRTC 0,1,2,3,4
        call testlongueurvbl    ;      0,1,1,0,0
        call testbfxx           ;      0,1,1,0,0,alien
        call testbexx           ;      0,0,0,1,1,alien
        call testfinvbl         ;      0,0,0,1,1,alien
        call testr4r5           ;      0,0,0,1,1,alien
        call testregswo         ;      0,0,0,1,1
        call testbloc           ;      0,0,0,1,1,alien
        call testborder         ;      0,1,0,0,0
        call testrazppi         ;      0,0,0,1,0,alien
        call testportbppi       ;      0,0,0,1,0
        call testreg31          ;      x,1,x,1,1
        ei
        ld a,(typecrtc)
        cp crtc0:jr z,type_0
        cp crtc1:jr z,type_1
        cp crtc2:jr z,type_2
        cp crtc3:jr z,type_3
        cp crtc4:jr z,type_4
        ld a,&f:ret
Type_0  ld a,0:ret
Type_1  ld a,1:ret
Type_2  ld a,2:ret
Type_3  ld a,3:ret
Type_4  ld a,4:ret
 
 
; Test basé sur la mesure de la longueur de VBL
; Permet de différencier les types 1,2 des 0,3,4
 
; Bug systématique
;   si le bit 7 du registre 3 est à zéro (double VBL)
;   le test renvoie un mauvais résultat
 
TestLongueurVBL
        ld b,&f5        ; Boucle d'attente de la VBL
SyncTLV1
        in a,(c)
        rra
        jr nc,synctlv1
NoSyncTLV1
        in a,(c)        ; Pre-Synchronisation
        rra             ; Attente de la fin de la VBL
        jr c,nosynctlv1
SyncTLV2
        in a,(c)        ; Deuxième boucle d'attente
        rra             ; de la VBL
        jr nc,synctlv2
 
        ld hl,140       ; Boucle d'attente de
WaitTLV dec hl          ; 983 micro-secondes
        ld a,h
        or l
        jr nz,waittlv
        in a,(c)        ; Test de la VBL
        rra             ; Si elle est encore en cours
        jp c,type12     ; on a un type 1,2...
        jp type034      ; Sinon on a un type 0,3,4
 
 
; Test basé sur la lecture des registres 12 et 13
; sur le port &BFxx
; Permet de différencier les types 0,3,4 et 1,2
 
; Limitation rare
;   si reg12=reg13=0 le test est sans effet
 
TestBFxx
        ld bc,&bc0c     ; On sélectionne le reg12
        out (c),c
        ld b,&bf        ; On lit sa valeur
        in a,(c)
        ld c,a          ; si les bits 6 ou 7 sont
        and &3f         ; non nuls alors on a un
        cp c            ; problème
        jp nz,typealien
        ld a,c
        or a            ; si la valeur est non nulle
        jp nz,type034   ; alors on a un type 0,3,4
        ld bc,&bc0d
        out (c),c       ; On sélectionne le reg13
        ld b,&bf
        in a,(c)        ; On lit sa valeur
        or a            ; Si la valeur est non nulle
        jp nz,type034   ; alors on a un type 0,3,4
        ret
 
 
; Test basé sur la lecture des registres 12 et 13
; à la fois sur les ports &BExx et &BFxx
; Permet de différencier les types 0,1,2 des 3,4
 
; Limitation rare
;   si reg12=reg13=0 le test est sans effet
 
TestBExx
        ld bc,&bc0c     ; On sélectionne le registre 12
        out (c),c       ; On compare les valeurs sur
        call cpbebf     ; les ports &BExx et &BFxx
        push af         ; (on sauve les flags)
        ld b,a          ; Si le bit 6 ou 7 de la valeur
        and &3f         ; lue pour &BFxx est non nul
        cp b            ; alors on a un problème
        call nz,typealien
        pop af          ; (on récupère les flags)
        jp nz,type012   ; Si elles sont différentes
        xor a           ; on a un type 0,1,2
        cp c            ; Si elles sont égales et
        jp nz,type34    ; non nulles on a un type 3,4
        ld bc,&bc0d     ; On sélectionne le registre 13
        out (c),c       ; On compare les valeurs sur
        call cpbebf     ; les ports &BExx et &BFxx
        jp nz,type012   ; Si elles sont différentes
        xor a           ; on a un type 0,1,2
        cp c            ; Si elles sont égales et
        jp nz,type34    ; non nulles on a un type 3,4
        ret
 
CPBEBF  ld b,&be        ; On lit la valeur sur &BExx
        in a,(c)
        ld c,a          ; On la stocke dans C
        inc b
        in a,(c)        ; On lit la valeur sur &BFxx
        cp c            ; On la compare à C
        ret
 
 
; Test basé sur la RAZ du PPI
; Permet de différencier les types 0,1,2,4 du 3
 
; Limitation systématique
;   l'état courant de configuration des ports
;   du PPI est perdu
 
TestRAZPPI
        ld bc,&f782     ; On configure le port C
        out (c),c       ; en sortie
        dec b
        ld c,&f         ; On place une valeur sur
        out (c),c       ; le port C du PPI
        in a,(c)        ; On vérifie si la valeur est
        cp c            ; toujours là en retour
        jp nz,typealien ; sinon on a un problème
        inc b
        ld a,&82        ; On configure de nouveau
        out (c),a       ; le mode de fonctionnement
        dec b           ; des ports PPI
        in a,(c)        ; On teste si la valeur placée
        cp c            ; sur le port C est toujours là
        jp z,type3      ; Si oui on a un type 3
        or a            ; Si elle a été remise à zéro
        jp z,type0124   ; on a un type 0,1,2,4
        jp typealien    ; Sinon on a un problème
 
 
; Test basé sur la détection du balayage des lignes
; hors border
; Permet d'identifier le type 1
 
; Bug connu rarissime
;   si reg6=0 ou reg6>reg4+1 alors le test est faussé !
 
TestBorder
        ld b,&f5
NoSyncTDB1
        in a,(c)        ; On attend un peu pour être
        rra             ; sur d'être sortis de la VBL
        jr c,nosynctdb1 ; en cours du test précédent
SyncTDB1
        in a,(c)        ; On attend le début d'une
        rra             ; nouvelle VBL
        jr nc,synctdb1
NoSyncTDB2
        in a,(c)        ; On attend la fin de la VBL
        rra
        jr c,nosynctdb2
 
        ld ix,0         ; On met à zéro les compteurs
        ld hl,0         ; de changement de valeur (IX),
        ld d,l          ; de ligne hors VBL (HL) et
        ld e,d          ; de ligne hors border (DE)
        ld b,&be
        in a,(c)
        and 32
        ld c,a
 
SyncTDB2
        inc de          ; On attend la VBL suivante
        ld b,&be        ; en mettant à jour les divers
        in a,(c)        ; compteurs
        and 32
        jr nz,border
        inc hl          ; Ligne de paper !
        jr noborder
Border  ds 4
NoBorder
        cp c
        jr z,nochange
        inc ix          ; Transition paper/border !
        jr change
NoChange
        ds 5
Change  ld c,a
 
        ds 27
 
        ld b,&f5
        in a,(c)
        rra
        jr nc,synctdb2  ; On boucle en attendant la VBL
 
        db &dd:ld a,l   ; Si on n'a pas eu juste deux
        cp 2            ; transitions alors ce n'est
        jp nz,type0234  ; pas un type 1
        jp type1        ; Pour plus de fiabilité au
                        ; regard de l'état de haute
                        ; impédance sur les CRTC autres
                        ; que le type 1 on pourrait
                        ; vérifier ici que HL vaut
                        ; reg6*(reg9+1) mais ça impose
                        ; de connaitre au préalable la
                        ; valeur de ces deux registres
 
 
; Test basé sur la lecture des registres 4 et 5
; Permet de différencier les types 0,1,2 des 3,4
 
; Limitation rare
;   si reg12=reg13=0 le test est sans effet
 
TestR4R5
        ld bc,&bc0c     ; On sélectionne le registre 12
        out (c),c       ; On compare les valeurs en
        call cprhrl     ; retour sur le port &BFxx
        push af         ; On sauve les flags
        ld b,a          ; Si le bit 6 ou 7 de la valeur
        and &3f         ; lue pour &BFxx est non nul
        cp b            ; alors on a un problème
        call nz,typealien
        pop af          ; On récupère les flags
        jp nz,type012   ; Si elles sont différentes
        xor a           ; on a un type 0,1,2
        cp c            ; Si elles sont égales et
        jp nz,type34    ; non nulles on a un type 3,4
        ld bc,&bc0d     ; On sélectionne le registre 13
        out (c),c       ; On compare les valeurs en
        call cprhrl     ; retour sur le port &BFxx
        jp nz,type012   ; Si elles sont différentes
        xor a           ; on a un type 0,1,2
        cp c            ; Si elles sont égales et
        jp nz,type34    ; non nulles on a un type 3,4
        ret
 
CPRHRL  ld b,&bf        ; On lit la valeur du registre
        in a,(c)        ; High sur &BFxx
        ld b,&bc        ; Sélection du registre Low
        res 3,c         ; On passe sur le registre Low
        out (c),c
        ld c,a          ; On la stocke dans C
        ld b,&bf
        in a,(c)        ; On lit la valeur sur &BFxx
        cp c            ; On la compare à C
        ret
 
 
; Test basé sur la valeur de retour sur les registres
; CRTC en écriture seule
; Permet de différencier les types 0,1,2 des types 3,4
 
; Aucune limitation/bug connus
 
TestRegsWO
        ld de,0         ; On lance le parcours des
        ld c,12         ; registres 0 à 11 avec
        call cumulereg  ; cumul de la valeur retour
        xor a           ; Si le résultat cumulé de
        cp d            ; la lecture est non nul
        jp nz,type34    ; alors on a un type 3,4
        jp type012      ; Sinon, c'est un type 0,1,2
CumuleReg
LoopTRI ld b,&bc        ; On sélectionne le
        out (c),e       ; registre "E"
        ld b,&bf        ; On lit la valeur
        in a,(c)        ; renvoyée en retour
        or d            ; On la cumule dans D avec
        ld d,a          ; les lectures précédentes
        inc e           ; On boucle jusqu'au
        ld a,e          ; registre "C"
        cp c
        jr nz,looptri
        ret
 
 
; Test basé sur la possibilité de programmer le port B
; en sortie
; Permet d'identifier le type 3
 
; Limitation systématique
;   l'état courant de configuration des ports
;   du PPI est perdu
 
TestPortBPPI
        ld b,&f5
SyncTPBP1
        in a,(c)
        rra
        jr nc,synctpbp1
NoSyncTPBP1
        in a,(c)        ; Pre-Synchronisation
        rra             ; Attente de la fin de la VBL
        jr c,nosynctpbp1
        ld bc,&f782     ; On configure le port B
        out (c),c       ; du PPI en entrée
        ld b,&f5        ; On lit la valeur présente
        in a,(c)        ; sur le port B puis on
        xor 254         ; la modifie judicieusement
        ld e,a          ; et on la stocke dans E
        ld d,&f5
        ld bc,&f780     ; On configure le port B
        out (c),c       ; du PPI en sortie
        ld b,d          ; On y envoie la valeur
        out (c),e       ; stockée dans E
        in a,(c)        ; On relit le port B
        ld bc,&f782     ; On reconfigure le port B
        out (c),c       ; du PPI en entrée
        cp e            ; Si la valeur E a été lue
        jp z,type0124   ; alors on a type 0,1,2,4
        jp type3        ; Sinon on a un type 3
 
 
; Test basé sur la détection de la dernière
; ligne de VBL
; Permet de différencier les types 0,1,2 des 3,4
 
; Bug systématique
;   si le bit 7 du registre 3 est à zéro (double VBL)
;   le test renvoie un mauvais résultat)
 
TestFinVBL
        ld bc,&bc0a     ; On sélectionne le
        out (c),c       ; registre 10 du CRTC
        ld b,&f5
NoSyncTFV1
        in a,(c)        ; Pre-Synchronisation
        rra             ; Attente de la fin de la VBL
        jr c,nosynctfv1
 
        ld b,&bf        ; On lit l'état du registre 10
        in a,(c)
        and 32          ; Si le bit5 est nul alors
        jp z,type012    ; on a un type 0, 1 ou 2
 
        ld b,&f5
SyncTFV2
        in a,(c)        ; Boucle d'attente de la VBL
        rra
        jr nc,synctfv2
 
        ld hl,55        ; Boucle d'attente de
WaitTfV dec hl          ; 388 micro-secondes
        ld a,h
        or l
        jr nz,waittfv
 
        ld b,&bf        ; On lit l'état du registre 10
        in a,(c)
        and 32          ; Si le bit5 est nul
        jp z,typealien  ; on a un problème
 
        ld b,13         ; Boucle d'attente de
        djnz $          ; 54 micro-secondes
 
        ld b,&bf        ; On lit l'état du registre 10
        in a,(c)
        and 32          ; Si le bit5 est non nul
        jp nz,typealien ; on a un problème
 
        ld b,13         ; Boucle d'attente de
        djnz $          ; 54 micro-secondes
 
        ld b,&bf        ; On lit l'état du registre 10
        in a,(c)
        and 32          ; Si le bit5 est non nul
        jp nz,type34    ; on a un type 3 ou 4
        jp typealien    ; Sinon on a un problème
 
 
; Test basé sur le statut particulier du registre 31
; Permet d'identifier les types 1, 3 et 4
 
; Limitation rarissime
;   ce test ne fournit pas de résultat sur type 1
;   si l'état de haute impédance est altéré
; Limitation courante
;   ce test ne fournit pas de résultat sur types 3 et 4
;   si le registre 15 est nul (ce qui est la valeur par
;   défaut)
 
TestReg31
        ld bc,&bc1f     ; On sélectionne le registre 31
        out (c),c       ; et on fait une tentative de
        ld b,&bf        ; lecture sur le port &BFxx
        in a,(c)        ; Si on a une valeur non nulle
        jp nz,type134   ; alors c'est un type 1,3,4
        ret             ; sinon on ne peut rien
                        ; conclure
 
 
; Test basé sur la détection des blocs 0 et 1
; Permet de différencier les types 0,1,2 des 3,4
 
; Limitation systématique
;   le registre 9 doit valoir 7 sinon le résultat
;   est faux
 
TestBloc
        ld bc,&bc0b     ; On sélectionne le
        out (c),c       ; registre 10 du CRTC
        ld b,&f5
NoSyncTB1
        in a,(c)        ; Pre-Synchronisation
        rra             ; Attente de la fin de la VBL
        jr c,nosynctb1
SyncTB2 in a,(c)        ; Boucle d'attente de la VBL
        rra
        jr nc,synctb2
NoSyncTB2
        in a,(c)
        rra             ; Attente de la fin de la VBL
        jr c,nosynctb2
 
        ld b,&bf        ; On lit l'état du registre 11
        in a,(c)        ; (on est sur le bloc 1)
        ld d,a
 
        ld b,14         ; On attend 58 micro-secondes
        djnz $
 
        ld b,&bf
        in a,(c)        ; On lit l'état du registre 11
        ld c,a          ; (on est sur le bloc 2)
 
        ld b,96         ; On attend 386 micro-secondes
        djnz $
 
        ld b,&bf
        in a,(c)        ; On lit l'état du registre 11
        ld e,a          ; (on est sur le bloc 0)
        or d            ; Si on n'a pas lu une valeur
        or e            ; nulle à chaque fois alors
        jr nz,tbactif   ; on peut continuer
        jp type012      ; Sinon on a un type 0, 1 ou 2
TBActif ld a,&a0        ; Si pour le bloc 0 on n'a pas
        and e           ; bit7=0 et bit5=0
        jp nz,typealien ; alors on a un problème
        ld a,&a0        ; Si pour le bloc 1 on n'a pas
        and d           ; bit7=1 et bit5=1
        cp &a0          ; alors on a un problème
        jp nz,typealien
        ld a,&a0        ; Si pour le bloc 2 on n'a pas
        and c           ; bit7=0 et bit5=1
        cp &20          ; alors on a un problème
        jp nz,typealien
        jp type34       ; Sinon on a un type 3 ou 4
 
 
; Routines de typage
 
CRTC0   Equ 1
CRTC1   Equ 2
CRTC2   Equ 4
CRTC3   Equ 8
CRTC4   Equ 16
 
Type012 ld a,(typecrtc)
        and crtc0+crtc1+crtc2
        ld (typecrtc),a
        ret
Type0124
        ld a,(typecrtc)
        and crtc0+crtc1+crtc2+crtc4
        ld (typecrtc),a
        ret
Type0234
        ld a,(typecrtc)
        and crtc0+crtc2+crtc3+crtc4
        ld (typecrtc),a
        ret
Type034 ld a,(typecrtc)
        and crtc0+crtc3+crtc4
        ld (typecrtc),a
        ret
Type1   ld a,(typecrtc)
        and crtc1
        ld (typecrtc),a
        ret
Type12  ld a,(typecrtc)
        and crtc1+crtc2
        ld (typecrtc),a
        ret
Type134 ld a,(typecrtc)
        and crtc1+crtc3+crtc4
        ld (typecrtc),a
        ret
Type3   ld a,(typecrtc)
        and crtc3
        ld (typecrtc),a
        ret
Type34  ld a,(typecrtc)
        and crtc3+crtc4
        ld (typecrtc),a
        ret
TypeAlien
        xor a
        ld (typecrtc),a
        ret
 
; Variables
 
        List
TypeCRTC
        db &ff
1) , 2) Hitachi
3) , 4) , 7) UMC
5) , 6) Motorola
8) , 9) La lecture renvoie 0
10) La lecture du registre 4 renvoie 0
11) Seuls les 3 bits de poids faibles sont décodés, par exemple lire le registre 4 renvoie sur le registre 12
12) Valeur de haute impédance non prévisible
13) , 14) Hi-Z, valeur de haute impédance
15) mirroir du port &BFXX
16) mirroir du port &BFxx
17) , 18) , 19) , 20) , 21) , 22) vers le bas
23) , 25) , 26) 0=normale, 1=double longueur
24) toujours double
27) , 29) La première ligne contient une alternance d'octets de border et de paper
28) Border sur tout l'écran
30) , 32) , 33) La valeur du registre 9 doit être décrémentée de 1 en compensation, et l'écran passe en 100Hz, les registres 4 et 7 doivent être doublés pour retomber sur 50Hz
31) L'écran passe en 100Hz, les registres 4 et 7 doivent être doublés pour retomber sur 50Hz
34) , 36) , 37) bits 4 et 5 à 1
35) R6 = 0
38) Pendant que C4 = 0, à l'écran suivant sinon
39) Pendant que C4 = 0, bufférisés sinon
40) uniquement si C4 > 0
41) utilisé dans les tests CRTC car il permet également d'identifier la machine, mais n'a pas grand chose à faire ici sinon
42) C'est le fameux “bug du PPI” qui empêche certains tests clavier de fonctionner sur CPC+