Gamoover

[move]Vous aimez la série Ricky la belle vie, Julio Iglésias ou l'émission Kohlanta ? Alors soyez les bienvenus sur Gamoover ! [/move]

Etude/Réalisation d'un générateur de mires 15/24/31 kHz

Démarré par gc339, Dimanche 27 Janvier 2013, 15:34:59 PM

gc339

J'utilise actuellement une version simplifiée du générateur vidéo décrit par Marcello Maggi, il permet de générer simplement 4 mires différentes en 15 kHz entrelacé : barres colorées, quadrillage, points ainsi qu'une image entièrement blanche :




   


Le dossier complet ou les fichiers isolés du générateur vidéo  sont disponibles à partir de plusieurs sites sur le net, il suffit de faire une recherche avec les mots clef "Marcello Maggi" et "video pattern generator".
A défaut voici le dossier pdf original sauvegardé ici sur le serveur Gamoover : http://www.gamoover.net/gc339/VidPatGen.pdf




Le générateur réalisé à partir de cette description :


Seul le pic 16F84 avec le programme original a été conservé, l'encodeur PAL inutile a été remplacé par un circuit intégré genre 26LS31 qui bufferise la synchro et les signaux RVB, ce qui me permet d'avoir deux sorties pour chaque signal : une normale (positive ) et la deuxième inversée (négative ).
Les deux switches Secme permettent de choisir une des 4 mires possibles.




Le problème est que ce générateur ne délivre que du 15 kHz et qu'il faudrait pouvoir générer les mêmes mires en 24 et en 31 kHz pour pouvoir tester les moniteurs multifréquences.
De plus la 4ème mire, celle affichant un écran uniformément blanc, n'est pas d'une très grande utilité. Il serait préférable de la remplacer par une mire alternant images ou larges bandes noires et blanches pour vérifier la stabilité de la THT :




   

En effet, une image noire demande aucun courant au bloc THT alors qu'une image uniformément blanche lui en soutire un maximum. Si le bloc THT est sous dimensionné ou mal en point, la tension s'affaissera avec le courant délivré, les électrons seront alors moins accélérés et seront donc plus facilement déviés par les bobinages du yoke, l'image affichée augmentera de taille et les zones blanches seront moins lumineuses.




L'objet de ce wip est de réaliser un générateur vidéo capable de délivrer les 3 mires de base plus la mire alternant zones blanches et noires et ceci aux 3 fréquences utilisées en arcade, 15, 24 et 31 kHz.

Le document de départ sera ce tableau extrait du "Service Manual" du moniteur MS-2931 donnant les timings des différents signaux vidéo, les trames sont toutes identiques, pas de trames paires et impaires car il n'y a pas d'entrelacement:




Seules les trois premières lignes horizontales du tableau sont utiles car elles concernent les signaux vidéo issus de systèmes Sega, ils serviront donc de référence pour l'élaboration de ce générateur.
Les 3 dernières lignes indiquent les timings correspondant à la taille d'image maximum que ce moniteur peut afficher.
Chaque ligne comporte deux cellules dans certaines colonnes verticales :

  • Les cellules du haut concerne la ligne. Elles indiquent la durée de l'impulsion de synchronisation ligne (Sync ), celle du contenu correspondant aux pixels affichés (Video ) avec son positionnement dans la ligne (B.P. pour Back Porch ), le tout exprimé en microsecondes.
  • Les cellules du bas concerne la trame. Elles délivrent la durée de l'impulsion de synchronisation (Sync ), la taille de l'image affichée  (Video )avec son positionnement dans la trame (B.P.), le tout exprimé en nombre de lignes.
Ainsi pour la première ligne du tableau décrivant un signal à 15 kHz :

  • L'impulsion de synchronisation ligne dure 4,75 µs, suivie 6,45 µs après par 49,17 µs du contenu à afficher. La ligne dure au total 63,56 µs et il reste donc 63,56 - 4,75 - 6,45 - 49,17 soit 3,19 µs entre la fin du contenu affiché et le début de l'impulsion ligne suivante.
  • L'impulsion de synchronisation trame dure 3 lignes, suivie 23 lignes vides après par 224 lignes de l'image à afficher. La trame dure au total 263 lignes et il reste donc 263 - 3 - 23 - 224 soit 13 lignes vides entre la fin de l'image affichée et le début de l'impulsion trame suivante




Les timings du signal vidéo à 15 kHz délivré par le précédent générateur étaient basés sur la durée des instructions du programme exécuté par le PIC 16F84 quitte à ajouter des instructions "nop" inopérantes pour ajuster les durées.
Ici les timings des lignes sont donnés à 0,01 µs près soit 10 ns ce qui correspondrait à une fréquence d'horloge de 100 Mhz pour un micro-contrôleur capable d'exécuter une instruction par cycle.
Le PIC16F84 du précédent générateur en est bien incapable avec sa plus grande fréquence d'horloge à 20 MHz, c'est pourquoi un SX28AC Scenix/Parallax/Ubicom lui sera substitué.
Ce micro-contrôleur SX28, en mode turbo, est capable d'exécuter une instruction par cycle d'horloge. Un SX28AC de base fonctionne parfaitement à une fréquence d'horloge de 50 MHz, certains exemplaires triés fonctionnent à 75 MHz voir même 100 MHz.
Avec un SX28AC de série cadencé à 50 MHz il sera donc possible d'exécuter une instruction toutes les 20 ns et ainsi de coller à ± 10 ns près au timing des signaux d'une ligne.


Le brochage du SX28AC avec son boîtier oscillateur externe.
20 ports d'E/S sont disponibles : 4 pour le port RA, 8 pour les ports RB et RC.




Le timing des signaux à 15 kHz sous forme graphique, page I-5 du "Service Manual" du moniteur MS-2931 :




Les quatre intervalles de temps exprimés en µs et recalculés en pas de 20 ns :

  • La synchronisation horizontale : 4,75 µs soit 4750 ns donc 237,5 pas.
  • Le palier de suppression arrière (back porch ): 6,45 µs donc 322,5 pas.
  • Le contenu à afficher : 49,17 µs donc 2458,5 pas.
  • Le palier de suppression avant (front porch ): 3,19 µs donc 159,5 pas.
Soit un total de 3178 pas de 20 ns pour une ligne complète. Un demi pas correspond en fait à 10 ns

Comme un pas correspondra à un cycle du SX28AC, chaque intervalle de temps doit être un nombre entier et il est préférable d'arrondir au nombre de pas immédiatement supérieur les intervalles de temps les plus courts , quitte à minorer les intervalles les plus longs, ainsi donc :

  • De 237,5 pas la synchronisation sera arrondie à 238.
  • De 322,5 pas le palier arrière sera arrondi à 323.
  • De 159,5 pas le palier avant sera arrondi à 160.
  • Il reste donc 3178 - (238 + 323 + 160) pas pour le contenu à afficher, soit 2457 pas.
Hors 2457 n'est pas divisible par 8, pourquoi par 8? Par ce que la mire à barre colorée comporte 8 barres. Ce qui ferait 307,125 pour chaque barre, si l'on arrondi à 307 pas par barre le total passe à 2456 pas et il faut soit augmenter d'un pas le palier avant soit le faire pour la dernière barre. En réalité cela n'a aucune importance pour cette mire car le palier avant est confondu avec la dernière barre puisque celle ci est de couleur noire :




Comme on peut le voir sur ce dessin représentant les 3 signaux RVB d'une mire à barre colorée, ces signaux ont une amplitude nulle quand la dernière barre, la noire, est affichée. Elle est donc au même niveau que celui de l'intervalle de temps séparant cette barre de l'impulsion de synchronisation, autrement dit elle est confondue avec le palier de suppression avant.




Le timing des signaux à 24 kHz, moitié supérieure de la page I-6 du "Service Manual" du moniteur MS-2931 :




Les quatre intervalles de temps exprimés en µs et recalculés en pas de 20 ns :

  • La synchronisation horizontale : 3,00 µs donc 150 pas.
  • Le palier de suppression arrière (back porch ): 4,44 µs donc 222 pas.
  • Le contenu à afficher : 30,69 µs donc 1534,5 pas.
  • Le palier de suppression avant (front porch ): 2,87 µs donc 143,5 pas.
Soit un total de 2050 pas de 20 ns pour une ligne complète.

Le nombre entier 1534 n'est pas divisible par 8, le plus proche multiple étant de 1536. En portant à 192 pas (1536 ÷ 8 = 192) l'intervalle de temps correspondant à chaque barre colorée, le palier de suppression avant devra alors être raboté de 1,5 pas soit 30 ns, ce qui n'est pas un problème puisque la dernière barre est confondue avec le palier de suppression avant.
Les intervalles de temps correspondant à l'impulsion de synchronisation ligne et au palier de suppression arrière restent inchangés puisque ce sont déjà des nombres entiers de pas, ainsi donc :

  • L'impulsion de synchronisation reste inchangée à 150 pas.
  • Le palier arrière reste inchangé à 222.
  • Le contenu à afficher est modifié à 8 × 172 soit 1536 pas.
  • Le palier avant est minoré de 1,5 pas, sa nouvelle valeur est de 142 pas soit 2,84 µs au lieu de 2,87 µs, ce qui représente une erreur de 1%.




Le timing des signaux à 31 kHz, moitié inférieure de la page I-6 du "Service Manual" du moniteur MS-2931 :




Les quatre intervalles de temps exprimés en µs et recalculés en pas de 20 ns :

  • La synchronisation horizontale : 3,58 µs donc 179 pas.
  • Le palier de suppression arrière (back porch ): 1,75 µs donc 87,5 pas.
  • Le contenu à afficher : 25,92 µs donc 1296 pas.
  • Le palier de suppression avant (front porch ): 0,33 µs donc 16,5 pas.
Soit un total de 1579 pas de 20 ns pour une ligne complète.

Le nombre entier 1296 est un multiple de 8, (1296 ÷ 8 = 162), il n'y a rien à retoucher. Par contre aucune durée des paliers de suppression ne correspond à un nombre entier et comme il est préférable de majorer le nombre le plus faible (16,5 pour le palier avant ) et de minorer le plus grand (87,5 pour le palier arrière ), cela aura pour effet négligeable de recentrer l'image affichée de 0,5 % ÷ 1296 soit 0,26 vers la gauche. Ainsi donc :

  • L'impulsion de synchronisation reste inchangée à 179 pas.
  • Le palier arrière est tronqué de 10 ns, sa nouvelle valeur est de 87 pas au lieu de 87,5.
  • Le contenu à afficher est reste inchangé, 8 × 162 soit 1296 pas.
  • Le palier avant est allongé de 10 ns, sa nouvelle valeur est de 17 pas au lieu de 16,5.




Le futur générateur en chantier :




Le circuit prépercé remplace le couvercle d'un boîtier de 120 × 75 × 55. Le boîtier du générateur précédent était plus petit puisqu'il ne mesurait que 90 × 60 × 40.

Pour l'instant ne sont implantés que :

  • Dans le coin supérieur gauche : le jack pour connecter le bloc secteur de l'alimentation extérieure
  • Au milieu toujours en haut, le régulateur 5 volts avec son radiateur.
  • En dessous à gauche, le module oscillateur 50 MHz récupéré sur une épave.
  • Toujours en dessous et à droite, le micro-contrôleur SX28AC Parallax.
Seront implantés par la suite :

  • Une embase HD-15 femelle pour sortir les signaux vidéo vers le moniteur en test.
  • Une batterie de 4 dip-switches, 2 pour choisir la mire et 2 autres pour la fréquence.
  • ...

Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard





kos71

oulalalal ça me plait bien ça . très bonne idée . je vais suivre ce post de pret car c 'est ideal pour le test d'écran . Il va m'en falloir un vu le nombre de wip que eyeshield me ramène en ce moment.

bon courage a toi pour la suite et surtout merci pour le partage de l'info et du concept
@home: Flip TMNT, flip hurricane, Flip big guns, flip dracula,Flip F14,robocop, lw3,jokerz, rockybullwinckle,star wars De,sttng,dr who,tales from the crypt,jurassic park,laser war,gateway,tommy the who,baby pacman./cab=Mortal kombat 2,hang on DX, time crisis, hotd,pupitre fighting vipers, Naomi 1,  cocktail RP,cocktail missile command , cocktail "taito", cocktail space trek,cocktail galaxian,cocktail DE deco,cocktail SI., twin sega rally, OUT RUN,cockpit OT turbo, Virtua cop, Euro 40, astro city Blast city,mvs4u,namco exceleena red,madonna,aerocityx2,sega city ,bandido et afterburner dx;

Persecutor

C'est vraiment une super idée  ^-^

et un sacré taff a venir  <:)

Les jeux de moto c'est nul ! Y'a pas de volant ...

Les bornes japonaises c'est comme les vaisseaux de la prélogie star wars,
c'est beau, lisse et parfaitement fonctionnel;
Alors que les bornes old school c'est un peu comme le Faucon Millenium qui passe jamais en vitesse lumière,
c'est chiant mais c'est tellement plus attachant ...

WIP s | Jeutel 25" RGB Jamma | Générique 17" 31khz | Mini BarTop TFT | Race Pod PC |

http://persecutor.tamdb.net

Eko

Ah Ahhhhh c'est reparti pour un projet qui va bien !!!!!!
<:) <:)

Bon, on se voit quand  =?= =?=  :D :D
Faut bien qu'on se fasse une bise pour la nouvelle année quand même  ;)
Et puis j'ai un truc à te faire visiter  :D j'ai fini... :D
Le RT, le WIP, des drogues dures ça nan ?

-RT Jeutel Mint !          -RT Twin STC          -WIP Twin STC         -RT Mini Jeutel    
-WIP Noami White       -WIP Noami Black    -WIP Gameroom      -WIP Mini Jeutel

gc339

#4
Autant commencer par le programme de la mire à barres colorées, c'est le plus simple!




Comme on peut le voir sur le dessin, les 8 couleurs de la mire à barre colorées sont générées à partir des 3 couleurs de base, leur présence ou leur absence détermine la teinte finale.
Un niveau logique 1 pour une couleur donnée équivaut à sa présence alors que le niveau 0 équivaut à son absence.
Dans le langage assembleur du SX28A, les couleurs peuvent être définies en binaire comme suit :

; Définition des couleurs de la mire à barres colorées

   Black   EQU   %000
BlueEQU%001   ; Bit 2°
RedEQU%010; Bit 2¹
GreenEQU%100; Bit 2²
MagentaEQUBlue+Red
CyanEQUBlue+Green
YellowEQURed+Green
WhiteEQUBlue+Red+Green

Le port RA du SX28AC étant arbitrairement choisi pour émettre les signaux de couleur, 3 de ses ports élémentaires se retrouvent affectés de fait suite à la définition qui a été donnée ci-dessus pour les couleurs de base :

  • RA0, patte n° 6, niveau logique de la couleur Bleue.
  • RA1, patte n° 7, niveau logique de la couleur Rouge.
  • RA2, patte n° 8, niveau logique de la couleur Verte.

Ainsi pour émettre une couleur ou en changer, l'instruction suivante pourra être employée :

   MOV   RA,#Cyan   ; Émission de la couleur Cyan

Le problème avec cette simple instruction est qu'elle affecte les 4 ports élémentaires du port RA dont fait partie RA3 qui n'est pas concerné par les informations de couleur. Il est préférable d'utiliser la séquence d'instructions suivante même si elle nécessite quelques cycles machine supplémentaires (W est le registre de travail ou accumulateur du micro-contrôleur ) :

   MOV   W,RA   ; Lecture du port RA
ANDW,#%1000; Effacement des 3 bits de couleur
ORW,#Cyan; Positionnement des seuls bits impactés par la couleur Cyan
MOVRA,W; Émission de cette nouvelle couleur




Le câblage entre le SX28AC et l'embase HD-15 femelle pourrait être réalisé comme suit :




Le buffer LS367A inséré entre les 3 ports du SX28AC et l'embase HD-15 permet de le protéger contre toute fausse manip. Il vaut mieux suicider un vulgaire LS367A coûtant une fraction d'euro que de bousiller le micro-contrôleur. D'ailleurs, il faudra certainement insérer un atténuateur commutable entre les sorties du LS367A et l'embase HD-15 car, selon les exigences du moniteur MS-2931, l'amplitude des signaux vidéo doit être limitée à 0,7 volt sur 75 ? en 24 et en 31 kHz. Ceci est à vérifier pour tout autre moniteur.




Dans le cas de la mire à barres colorées un délai doit être mis en oeuvre entre chaque changement de couleur, cette temporisation déterminera la largeur des barres verticales :

Exemple cette séquence d'instructions :


Start   MOV   RA,#White   ; Émission de la barre Blanche
CALLDelay
MOVRA,#Yellow; Émission de la barre Jaune
CALLDelay
MOVRA,#Cyan; Émission de la barre Cyan
CALLDelay
MOVRA,#Green; Émission de la barre Verte
Et ainsi de suite pour les autres couleurs...

Comme évoqué dans le message précédent, ces délais ou temporisations sont basées sur la durée que met le micro-contrôleur à exécuter une bouclette de programme. Généralement on utilise une variable, préalablement déclarée en entête de programme, qui sera pré-positionnée pour être ensuite décrémentée jusqu'à ce que sa valeur soit nulle. Exemple :


Start   MOV   RA,#White   ; Émission de la barre Blanche
MOVCounter,#Delay; Initialisation du compteur
LoopWhiteDJNZCounter,LoopWhite
NOP
NOP
MOVRA,#Yellow; Émission de la barre Jaune
MOVCounter,#Delay; Initialisation du compteur
LoopYellowDJNZCounter,LoopYellow
NOP
NOP
MOVRA,#Cyan; Émission de la barre Cyan
Et ainsi de suite pour les autres couleurs...

L'instruction DJNZ (Decrement and Jump if Non Zero) est celle de la bouclette, elle décrémente la variable "Counter" et reboucle à l'adresse "LoopWhite", c'est à dire sur elle même, jusqu'à ce que la variable atteigne zéro. Comme cette instruction DJNZ nécessite plusieurs cycles d'horloge, des instructions NOP (qui font rien du tout sauf consommer un cycle d'horloge ), ont été ajoutées à sa suite pour ajuster au cycle près la durée de la temporisation.




Plutôt que de répéter X fois la même séquence d'instructions, il est préférable de les regrouper sous une macro. Macro qui sera déclarée en tête de programme et appelée autant de fois que nécessaire dans le programme, exemple :


SetColor   MACRO   Color,Delay   ; Déclaration de la macro et de ses deux paramètres
LOCALLocLoop; Étiquette interne à la macro
MOVW,RA; Lecture du port RA
ANDW,#%1000; Effacement des 3 bits de couleur
ORW,#Color; Positionnement des seuls bits impactés par la nouvelle couleur
MOVRA,W; Émission de cette nouvelle couleur
MOVCounter,#Delay; Initialisation du compteur
LocLoopDJNZCounter,LocLoop
NOP
NOP
ENDM

Avec une temporisation fantaisiste de 100 choisie pour cet exemple, l'émission des 8 barres colorées pourra s'écrire plus simplement,  :

Start   SetColor   White,100
SetColorYellow,100
SetColorCyan,100
SetColorGreen,100
SetColorMagenta,100
SetColorRed,100
SetColorBlue,100
SetColorBlack,100

Les intervalles de suppression correspondent en fait à l'émission d'aucun bit de couleur donc à l'émission de la couleur noire. Il n'est alors pas utile de dissocier l'émission de la dernière barre de celle du palier de suppression avant, elle et il peuvent être regroupés en une seule émission de la couleur noire avec augmentation de la temporisation en conséquence, la séquence devient alors :

Start   SetColor   Black,30   ; Émission du palier de suppression arrière, durée 30
SetColorWhite,100
SetColorYellow,100
SetColorCyan,100
SetColorGreen,100
SetColorMagenta,100
SetColorRed,100
SetColorBlue,100
SetColorBlack,100+20; Palier de suppression avant accolé à dernière bande, durée 20




Pour l'exemple, les délais passés à la macro étaient fantaisistes. Il va falloir maintenant utiliser les pas calculés dans le précédent post pour chaque fréquence de balayage et faire en sorte que la macro puisse s'en servir directement pour éviter à chaque fois des calculs fastidieux.

Il est nécessaire de quantifier la durée de la macro "SetColor" en nombre de cycles :


SetColor   MACRO   Color,Delay   
LOCALLocLoop
MOVW,RA; 1 cycle
ANDW,#%1000; 1 cycle
ORW,#Color; 1 cycle
MOVRA,W; 1 cycle
MOVCounter,#Delay; 2 cycles
LocLoopDJNZCounter,LocLoop; 4 cycles sinon 2 en sortie de boucle
...
ENDM

Ce qui donne : 1 + 1 + 1 + 1 + 2 + (4 × (Delay-1)) + 2 cycles, ce qui se simplifie en : 4 × (Delay+1)

Autrement dit, une unité du paramètre "Delay" équivaut actuellement à 4 cycles d'horloge. Si l'on veut qu'une unité de "Delay" corresponde à un pas ou cycle, il va falloir diviser le nombre de bouclettes par 4 moins une et rajouter de 1 à 3 "NOP" pour affiner la temporisation au plus près :


SetColor   MACRO   Color,Delay   ; Déclaration de la macro et de ses deux paramètres
LOCALLocLoop; Étiquette interne à la macro
MOVW,RA; Lecture du port RA
ANDW,#%1000; Effacement des 3 bits de couleur
ORW,#Color; Positionnement des seuls bits impactés par la nouvelle couleur
MOVRA,W; Émission de cette nouvelle couleur
MOVCounter,#((Delay/4)-1); Initialisation du compteur de bouclettes
LocLoopDJNZCounter,LocLoop
REPTDelay//4; Affinage, répétition de NOP modulo 4
NOP
ENDR
ENDM

L'opérateur "/" effectue une division ayant un nombre entier comme résultat alors que l'opérateur "//" ou modulo permet de récupérer le reste de cette même division. Ainsi la macro peut calculer automatiquement le nombre de bouclettes adéquates et insérer l'appoint en instructions "NOP".




Avec le nombre de pas calculés dans le post précédent, une ligne de la mire à barres colorées peut s'exprimer ainsi pour la fréquence de 15 kHz :


Start   SetColor   Black,323   ; Émission du palier de suppression arrière, durée 323 cycles
SetColorWhite,307
SetColorYellow,307
SetColorCyan,307
SetColorGreen,307
SetColorMagenta,307
SetColorRed,307
SetColorBlue,307
SetColorBlack,307+161; Palier de suppression avant accolé à dernière bande, durée 161 cycles

On peut même pousser le luxe en englobant cette série de macros dans une nouvelle macro à laquelle on ne fourni que les paramètres de durée des différents intervalles :


ColorBars   MACRO   DelayBP,DelayBar, DelayFP   ; Déclaration de la macro et de ses trois paramètres
   SetColor   Black,DelayBP   ; Émission du palier de suppression arrière (BP as Back Porch)
SetColorWhite,DelayBar
SetColorYellow,DelayBar
SetColorCyan,DelayBar
SetColorGreen,DelayBar
SetColorMagenta,DelayBar
SetColorRed,DelayBar
SetColorBlue,DelayBar
SetColorBlack,DelayBar+DelayFP; Palier de suppression avant accolé à dernière bande (FP as Front Porch)
ENDM

Ainsi pour générer la même ligne en 15 kHz il suffira d'écrire (après avoir écrit toutes les déclarations nécessaires ) :


Bars15   ColorBars   323,307,161   ; Émission d'une ligne à 15 kHz de la mire à barres colorées




Aussi simple pour générer une ligne en 24 et en 31 kHz :


Bars24   ColorBars   222,172,142; Émission d'une ligne à 24 kHz de la mire à barres colorées
Bars31ColorBars87,122,17   ; Émission d'une ligne à 31 kHz de cette même mire.

Bon maintenant il ne reste plus qu'à intégrer l'impulsion de synchronisation dans la ligne et à répéter les lignes autant de fois que nécessaire pour constituer la trame.
Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard





gc339

#5
Un petit retour en arrière sur la macro "SetColor" ou plus exactement sur les deux lignes de code (en bleu) qui réalisent la temporisation :


SetColor   MACRO   Color,Delay   ; Déclaration de la macro et de ses deux paramètres
LOCALLocLoop; Étiquette interne à la macro
MOVW,RA; Lecture du port RA
ANDW,#%1000; Effacement des 3 bits de couleur
ORW,#Color; Positionnement des seuls bits impactés par la nouvelle couleur
MOVRA,W; Émission de cette nouvelle couleur
MOVCounter,#((Delay/4)-1); Initialisation du compteur de bouclettes
LocLoopDJNZCounter,LocLoop
REPTDelay//4; Affinage, répétition de NOP modulo 4
NOP
ENDR
ENDM

La taille de la variable "Counter" étant d'un octet, elle ne peut servir à décompter que 256 bouclettes au maximum, la temporisation s'étage donc entre (1 + 1) × 4 = 8  et (1 + 25) × 4 = 1028 cycles d'horloge par sauts de 4 en 4.
Ces 1028 cycles ou pas maximum ne seront pas suffisants dans le cas de la mire clignotante où toutes les lignes sont uniformes pendant un intervalle de temps aussi grand que 2456 pas dans le cas du 15 kHz.
Il convient donc de réécrire cette macro et d'en profiter pour isoler les lignes de code de la temporisation dans une nouvelle macro spécifique afin d'éviter leur répétition intempestive dans le programme source.

Tout d'abord les deux lignes (en bleu) peuvent être isolées dans une sous-macro indépendante :
 

BasicDelay   MACRO   Value   ; Déclaration de la macro et de son paramètre
LOCALLocLoop; Étiquette interne à la macro
MOVLoopCounter,#Value; 2 cycles, initialisation du compteur de bouclettes
LocLoopDJNZLoopCounter,LocLoop; 4 cycles sinon 2 en sortie de boucle
ENDM

Le nom de la variable "Counter" évolue en LoopCounter pour l'identifier immédiatement par rapport aux autres compteurs "LineCounter" et "FrameCounter" qui seront utilisés par la suite.
La temporisation, en nombre de cycles, réalisée par cette macro de base est tout simplement égale à 4 fois la valeur paramétrée.

La temporisation maximum réalisable par cette macro est donc de 1024 cycles d'horloge (256 × 4). Plutôt que de décompter, avec un deuxième compteur, le nombre de fois ou une telle macro sera utilisée, il est plus simple d'en accoler plusieurs à la suite surtout qu'un nombre raisonnable de trois sera nécessaire pour atteindre la temporisation de 2456 pas évoquée plus en avant.

En choisissant une valeur maximum de 250 au lieu de 256, ce qui correspond au nombre bien bien plus pratique de 1000 cycles, la temporisation voulue pourra être ainsi exprimée :

      REPT   Value/250   ; Correspond à 250 × 4 soit 1000 cycles d'horloge
 BasicDelay250
ENDR
BasicDelayValue//250; Complémenté par le reste de la division par 250

A fin d'éviter à l'assembleur de recalculer à chaque fois l'expression ((Delay/4)-1) on peut assigner cette expression à un symbole redéfinissable, ici "Loops", grâce à la directive "SET" :

Loops   SET   (Delay/4)-1
REPTLoops/250   ; Correspond à 250 × 4 soit 1000 cycles d'horloge
 BasicDelay250
ENDR
BasicDelayLoops//250; Complémenté par le reste de la division par 250

Chaque boucle élémentaire consommant 4 cycles d'horloge, il faut rajouter l'affinage final à la nouvelle macro "Wait" qui va maintenant gérer les temporisations :


Wait   MACRO   Delay   ; Déclaration de la macro et de son paramètre
Loops   SET   (Delay/4)-1
REPTLoops/250   ; Correspond à 250 × 4 soit 1000 cycles d'horloge
 BasicDelay250
ENDR
BasicDelayLoops//250; Complémenté par le reste de la division par 250
REPTDelay//4; Affinage, répétition de NOP modulo 4
 NOP
ENDR
ENDM

Ainsi la précédente macro "SetColor" peut maintenant s'écrire :


SetColor   MACRO   Color,Delay   ; Déclaration de la macro et de ses deux paramètres
MOVW,RA; 1 cycle, lecture du port RA
ANDW,#%1000; 1 cycle, effacement des 3 bits de couleur
ORW,#Color; 1 cycle, positionnement des seuls bits impactés par la nouvelle couleur
MOVRA,W; 1 cycle, émission de cette nouvelle couleur
WaitDelay; Temporisation, tient compte des 4 cycles absorbés par les instructions précédentes
ENDM




La nouvelle macro dédiée à la temporisation inclus dans son calcul de boucles un offset qui correspond aux 4 cycles des instructions l'ayant précédé. Ces instructions ayant permis de changer de couleur, voici une représentation explicitant l'impact de ce décalage sur l'affichage des barres colorées de la mire :




La nouvelle couleur n'est émise qu'après exécution de l'instruction "MOV  RA,W", et comme le décalage de 4 cycles est systématique pour chaque nouvelle couleur, les durées sont toujours respectées au cycle près.
Le traitement de la synchronisation horizontale devra de fait être calqué sur celui des barres colorées et assumer ce même décalage.





  • A l'extrême gauche la représentation de la fin de la dernière barre de la mire : la barre noire.
  • Ensuite débute l'enchaînement de 3 intervalles de temps communs à toutes les différentes mires :

    • Le palier de suppression avant, l'émission de la couleur noire est impérative pour la raison évoquée ci-dessus car la couleur précédente peut être différente.
    • L'impulsion de synchronisation, la couleur restant noire, inutile de l'émettre à nouveau. L'intervalle de 4 cycles qu'occupait cette opération est mis à profit pour émettre cette impulsion :

      • 3 cycles sont absorbés par une instruction qui n'exécute qu'un saut sur la suivante :

              JMP   $+1   ; Absorpsion de 3 cycles
        Le sigle "$" représentant l'adresse de l'instruction "JMP", $+1 représente donc celle de la suivante
      • La dernière est une manipulation de bit qui positionne le port associé à la synchronisation horizontale :

              SETB   SyncH   ; Emission de l'impulsion
        Ce port aura préalablement été déclaré en tête de programme :

           SyncH   EQU   RB.0   ; Synchronisation horizontale, port RB0, patte 10
        SyncVEQURB.1; Synchronisation verticale, port RB1, patte 11
    • Le palier de suppression arrière. Il efface l'impulsion de synchronisation horizontale après absorpsion de 3 cycles par une instruction "JMP".

            JMP   $+1   ; Absorpsion de 3 cycles
      CLRBSyncH; Effacement de l'impulsion
  • Et enfin à l'extrême droite la figuration du début de la première bande de la ligne suivante, la barre blanche.




Avec la précédente macro ColorBars réécrite sans les paliers de suppression :


ColorBars   MACRO   DelayBar   ; Déclaration de la macro et de son unique paramètre
SetColorWhite,DelayBar; Première barre verticale
SetColorYellow,DelayBar
SetColorCyan,DelayBar
SetColorGreen,DelayBar
SetColorMagenta,DelayBar
SetColorRed,DelayBar
SetColorBlue,DelayBar
SetColorBlack,DelayBar; La huitième barre est aussi la dernière
ENDM

Avec le nombre de pas calculés dans le premier post, la définition dans le post précédent d'une ligne de la mire à barres colorées peut être réexprimée ainsi pour la fréquence de 15 kHz :


                  ; Palier de suppression arrière (Back Porch)
JMP$+1; Absorpsion de 3 cycles
CLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Affichage des 8 barres colorées de la mire
ColorBars307; Affichage de la mire, chaque barre occupe un intervalle de 307 cycles
; Palier de suppression avant (Front Porch)
SetColorBlack,161; Suppression de la dernière couleur par forçage du noir, durée du palier 161 cycles
; Impulsion de synchronisation horizontale
JMP$+1; Absorpsion de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes

En réordonnant les instructions afin d'utiliser un des sauts absorbateur pour assurer indéfiniment le rebouclage de la séquence :


                  ; Palier de suppression arrière (Back Porch), suite
LineLoopCLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Affichage des 8 barres colorées de la mire
ColorBars307; Affichage de la mire, chaque barre occupe un intervalle de 307 cycles
; Palier de suppression avant (Front Porch)
SetColorBlack,161; Suppression de la dernière couleur par forçage du noir, durée du palier 161 cycles
; Impulsion de synchronisation horizontale
JMP$+1; Absorpsion de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPLineLoop; Rebouclage avec absorpsion de 3 cycles

Les durées des différents intervalles d'une ligne sont ainsi respectés au cycle près, la prochaine étape consistera à compter les lignes pour déterminer les différents intervalles d'une trame.




Le câblage prévu pour raccorder les synchronisations sur l'embase HD-15 en profitant des deux derniers buffers dans le LS367 :







Après assemblage du code source, simulation avec le simulateur SXSim pour vérification des temporisations et enfin programmation d'un SX28AC avec le programmateur Fluffy-2, voici les différents signaux échantillonnés à 20 MHz par le Scanalogic 2 pour une fréquence ligne de 15 kHz :

  • CH1/trace bleue pour le signal du bleu.
  • CH2/trace jaune pour la synchronisation horizontale.
  • CH3/trace rouge pour le signal du rouge.
  • CH4/trace verte pour le signal du vert.
A comparer avec les chronogrammes du dessin inclus en tête du post précédent.







Par contre quand ces mêmes signaux sont visualisés à l'oscilloscope, ils sont beaucoup moins lisses, le palier correspondant au niveau logique haut n'est pas exempt de "glitches"

Par exemple pour le signal du bleu :




Avec une résistance de 4,7 kΩ entre la masse et la sortie concernée du LS367 pour soutirer un peu de courant au transistor qui assure le niveau haut, les "glitches" disparaissent et le palier redevient plat, quoique le niveau correspondant se soit affaissé de quelques dixièmes de volt.




Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard





pn_jeux

Bonjour, cela me rappelle que j'avais réalisé un petit programme de mires sur Atari st, il est vrai que ces microcontrôleurs Scenix ont une puissance de calcul phénoménale, certains ont réussi à programmer des jeux vidéo. Fameux travail, en tout cas... ^-^

gc339

Citation de: pn_jeux le Vendredi 01 Février 2013, 12:13:54 PMil est vrai que ces microcontrôleurs Scenix ont une puissance de calcul phénoménale, certains ont réussi à programmer des jeux vidéo.


Non seulement le µC SX exécute le programme du jeu en affichant les scores, mais il arrive à générer la sous-porteuse NTSC/PAL avec le reste de cycles machine disponibles car il délivre en sortie un signal couleur en vidéo composite acceptable directement par une TV !
Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard





Shuff

Très instructif et détaillé ce topic.
Merci de partager ce travail avec nous gc339  <:)

CkurcK

Wouaw merci pour ce partage !

C'est pour ça que j'aime Gamo !!!  :-)=

nc333

Je propose quelque amélioration:
_afficher le bord du quadrillage en une autre couleur, effectivement quand l'écrans est très déréglé on ne peut savoir si l'image est décentré de un ou deux carreau

_Garder une page blanche en plus, peut s'avérer utile pour mètre en évidence le marquage du tube ou pour réglé la luminosité de la THT

_ Faire un dégradé de chaque couleur, pour régler les cut-offs

_Mettre le montage sur batterie  :)

Je suis toujours impressionné par le niveau de tes réalisation.
"Bon, j'ai pas mal réfléchi. Quand la vie vous fait trébucher, ça ne suffit pas de se relever. Il faut lui péter les rotules, à cette grognasse ! Œil pour œil, dent pour dent ! « Essaie un peu de te relever, maintenant, traînée ! »" Caves Johnson, 1980


La présentation c'est ICI :)

gc339

#11
Une trame ne comporte pas que des lignes dont le contenu est représentatif, elle est aussi composée de lignes inertes encadrant celles consacrées à la synchronisation verticale dont le contenu est forcé au niveau du noir. Le bloc de lignes représentant une période quelconque de la trame, pourra être redéfini ainsi (pour une mire à 15 kHz ):


                  ; Palier de suppression arrière (Back Porch), suite
LineLoopCLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Période d'affichage
IFDisplayPatten=1
 ColorBars307; Affichage de la mire, chaque barre occupe un intervalle de 307 cycles
ELSE
 SetColorBlack,2456; Niveau du noir imposé pendant 2456 cycles
ENDIF
; Palier de suppression avant (Front Porch)
SetColorBlack,161; Suppression de la dernière couleur par forçage du noir, durée du palier 161 cycles
; Impulsion de synchronisation horizontale
JMP$+1; Absorption de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPLineLoop; Rebouclage avec absorption de 3 cycles

Le problème vient du fait que ce bloc boucle indéfiniment sur lui-même sans jamais enchaîner sur un autre, il est donc nécessaire de lui insérer un comptage pour que le contrôle échoie au bloc suivant une fois le bon nombre de lignes déroulées atteint.
Mais avant de réaliser cette inclusion, il est nécessaire de différencier chaque bloc de lignes par une étiquette globale. Les étiquettes suivantes seront déclarées locales à ce même bloc en les préfixant par deux points verticaux ":" ce qui devrait permettre de réutiliser localement les mêmes noms sans conflit dans les autres blocs :


BlockDraft     EQU     $     ; Étiquette globale en entête du bloc d'instructions
; Palier de suppression arrière (Back Porch), suite
:Loop  CLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Période d'affichage
IFDisplayPatten=1
 ColorBars307; Affichage de la mire, chaque barre occupe un intervalle de 307 cycles
ELSE
 SetColorBlack,2456; Niveau du noir imposé pendant 2456 cycles
ENDIF
; Palier de suppression avant (Front Porch)
SetColorBlack,161; Suppression de la dernière couleur par forçage du noir, durée du palier 161 cycles
; Impulsion de synchronisation horizontale
:Start  JMP$+1; Absorption de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMP:Loop  ; Rebouclage local avec absorption de 3 cycles

Ainsi les deux étiquettes "Loop" et ":Start" seront locales à ce bloc mais pourront être connues des autres comme étiquettes globales si on les préfixe par celle du bloc d'instructions auquel elles appartiennent, exemple : "BlockDraft:Start"
L'emplacement le plus judicieux pour insérer le comptage se situe à la fin du palier avant de la suppression ligne auquel il devra emprunter quelques cycles machine.
Deux cas de figure après décomptage d'une ligne :

  • LineCounter ≠ 0, l'enchaînement est repris dans le même bloc à partir de son étiquette ":Start"
  • LineCounter = 0, le compteur est rechargé avec le nombre de lignes de la période suivante et l'enchaînement est transféré sur l'étiquette ":Start" du bloc suivant.




Mais il y a échec lors de l'assemblage car les étiquettes locales ne le sont qu'à la suite d'instructions précédée par une étiquette globale et le drame vient du fait que les macros sont aussi considérées comme des étiquettes globales, ainsi les étiquettes ":Loop" et "Start" ne sont plus locales à la même suite d'instructions puisque celle-ci à été fractionnée par les macros invoquées entre-temps.
L'astuce trouvée, quoique pas très orthodoxe, a été de redéfinir l'étiquette globale après invocation des macros à l'aide d'une seconde directive "SET" :


BlockDraft     SET     $     ; Étiquette globale en entête du bloc d'instructions
; Palier de suppression arrière (Back Porch), suite
:Loop  CLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Période d'affichage
IFDisplayPatten=1
 ColorBars307; Affichage de la mire, chaque barre occupe un intervalle de 307 cycles
ELSE
 SetColorBlack,2456; Niveau du noir imposé pendant 2456 cycles
ENDIF
; Palier de suppression avant (Front Porch)
SetColorBlack,161; Suppression de la dernière couleur par forçage du noir, durée du palier 161 cycles
BlockDraft  SET  $  ; Étiquette globale redéfinie sur cette nouvelle adresse
; Impulsion de synchronisation horizontale
:Start  JMP$+1; Absorption de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPBlockDraft:Loop  ; Rebouclage avec absorption de 3 cycles

Ainsi les deux étiquettes locales impliquées semblent appartenir en première lecture au même bloc d'instructions alors que l'assembleur fait bien la distinction et assemble le code sans générer une quelconque erreur.




Étant donné que le compteur devra pouvoir compter jusqu'à 480 lignes avec le 31 kHZ, un seul octet ne sera pas suffisant, il faut donc le prévoir sur un mot de 2 octets :


      ORG   8   ; Début de mémoire utilisable
LoopCounterDS1; Compteur de boucles
LineCounterDS2; Compteur de lignes
FrameCounterDS1; Compteur de Trames

En fait le compteur ne comptera pas les lignes mais les décomptera, leur nombre ayant été préalablement initialisé par le bloc précédent avant de transférer l'exécution dans celui-ci.
La suite d'instructions suivantes gérant ce comptage est destinée à être incluse dans n'importe quel bloc de la trame, en fin du palier de suppression avant comme cela a été projeté :


      DJNZ   LineCounter,Label1   ; -1 sur octet de poids faible
TESTLineCounter+1; Test sur l'octet de poids fort
JZLabel2
DECLineCounter+1; -1 sur octet de poids fort
SKIP; 6 cycles déjà consommés, 8 à absorber pour atteindre l'adresse :Start
Label1JMP$+2; 4 cycles déjà consommés, 10 à absorber pour atteindre l'adesse :Start
SKIP
JMP$+1
NOP
JMPBlock:Start; Étiquette locale du bloc où cette suite d'instruction a été insérée
Label2MOVLineCounter,#(Value//256); Chargement du compteur, octet de poids faible
MOVLineCounter+1,#(Value/256); Idem, octet de poids fort
JMPNextBlock:Start; Étiquette locale du bloc suivant où l'exécution doit être transférée

Le nombre de cycles le plus grand de cette suite d'instructions est celui du traitement où le compteur a atteint zéro et il est dans ce cas égal à 14. Aux autres cas de figure doivent correspondre le même temps d'exécution, c'est pour cela qu'ils ont été ajustés au cycle près par l'insertion d'instructions inertes comme NOP (1 cycle ), SKIP (2 cycles ) et JMP (3 cycles )

Cette suite d'instructions testant le compteur de lignes peut-être transformé en macro invoquable par les différents blocs dont une trame est constituée :


NextLine   MACRO   CurrentBlock,NextBlock, NewLineNumber   
LOCALLabel1,Label2; Déclaration des étiquettes privées
DJNZLineCounter,Label1; -1 sur octet de poids faible
TESTLineCounter+1; Test sur l'octet de poids fort
JZLabel2
DECLineCounter+1; -1 sur octet de poids fort
SKIP; 6 cycles déjà consommés, 8 à absorber pour atteindre l'adresse :Start
Label1JMP$+2; 4 cycles déjà consommés, 10 à absorber pour atteindre l'adresse :Start
SKIP
JMP$+1
NOP
JMPCurrentBlock??:Start; Étiquette locale du bloc où cette suite d'instruction a été insérée
Label2MOVLineCounter,#(NewLineNumber//256); Chargement du compteur, octet de poids faible
MOVLineCounter+1,#(NewLineNumber/256); Idem, octet de poids fort
JMPNextBlock??:Start; Étiquette locale du bloc suivant où l'exécution doit être transférée
ENDM

L'opérateur "??" permet de concaténer le nom de l'étiquette globale passée en tant que paramètre à celui de l'étiquette locale accolée à la suite en temps que texte.




On peut maintenant juxtaposer les différents blocs pour écrire le code d'une trame de la mire à barre colorées.
Le nombre de lignes de chaque bloc est issu du timing des signaux à 15 kHz joint au premier post de ce wip :


FrameStart   JMP   LeadingField:Start

;------------------------------------------ Blanking avant ----------------------------------------


LeadingField   SET   $
   ; Palier de suppression arrière (Back Porch), suite
:LoopCLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Blanking des lignes précédant l'impulsion trame
SetColorBlack,2456; Contenu des lignes forcé au niveau du noir pendant le blanking trame
; Palier de suppression avant (Front Porch)
SetColorBlack,161-14; Palier forcé au niveau du noir, prise en compte des 14 cycles du décomptage
LeadingFieldSET$; Décomptage des lignes du bloc en fin du palier (14 cycles)
NextLineLeadingField,SyncField,3; Durée de 3 lignes pour l'impulsion de synchronisation verticale
; Impulsion de synchronisation horizontale
:StartJMP$+1; Absorption de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPLeadingField:Loop; Rebouclage avec absorption de 3 cycles

;------------------------------ Impulsion de synchronisation trame --------------------------------


SyncField   SET   $
   ; Palier de suppression arrière (Back Porch), suite
:LoopCLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Blanking des lignes pendant l'impulsion de synchronisation trame
SetColorBlack,2456; Contenu des lignes forcé au niveau du noir pendant l'impulsion de synchronisation trame
; Palier de suppression avant (Front Porch)
SetColorBlack,161-14; Palier forcé au niveau du noir, prise en compte des 14 cycles du décomptage
SyncFieldSET$; Décomptage des lignes du bloc en fin du palier (14 cycles)
NextLineSyncField,LaggingField,23; Durée de 23 lignes pour le blanking arrière
; Impulsion de synchronisation horizontale
:StartJMP$+1; Absorption de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPSyncField:Loop; Rebouclage avec absorption de 3 cycles

;----------------------------------------- Blanking arrière ---------------------------------------


LaggingField   SET   $
   ; Palier de suppression arrière (Back Porch), suite
:LoopCLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Blanking des lignes à la suite de l'impulsion trame
SetColorBlack,2456; Contenu des lignes forcé au niveau du noir pendant le blanking trame
; Palier de suppression avant (Front Porch)
SetColorBlack,161-14; Palier forcé au niveau du noir, prise en compte des 14 cycles du décomptage
LaggingFieldSET$; Décomptage des lignes du bloc en fin du palier (14 cycles)
NextLineLaggingField,PatternField,224; Durée de 224 lignes pour afficher la mire à barres colorées
; Impulsion de synchronisation horizontale
:StartJMP$+1; Absorption de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPLaggingField:Loop; Rebouclage avec absorption de 3 cycles

;---------------------------------------- Affichage de la mire --------------------------------------


PatternField   SET   $
   ; Palier de suppression arrière (Back Porch), suite
:LoopCLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Affichage des 8 barres colorées de la mire
ColorBars307; Affichage de la mire, chaque barre occupe un intervalle de 307 cycles
; Palier de suppression avant (Front Porch)
SetColorBlack,161-14; Palier forcé au niveau du noir, prise en compte des 14 cycles du décomptage
LaggingFieldSET$; Décomptage des lignes du bloc en fin du palier (14 cycles)
NextLinePatternField,LeadingField,13; Durée de 13 lignes pour le blanking avant
; Impulsion de synchronisation horizontale
:StartJMP$+1; Absorption de 3 cycles
SETBSyncH; Émission de l'impulsion
Wait238; Durée de l'impulsion, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPPatternField:Loop; Rebouclage avec absorption de 3 cycles

D'emblée on se rend compte que le palier arrière d'une ligne peut être confondu avec son contenu car il sont tous les deux forcés au niveau du noir pendant les périodes de suppression trame ou blanking : lignes écrites en bleu.
A ce propos, le simulateur SXSim a permis de faire ressortir un problème au niveau de l'assembleur, l'expression "161-14" passée comme paramètre à la macro SetColor n'est pas évaluée par celle-ci, mais par la macro fille "Wait" qui applique la précédence des opérateurs dans ses calculs, ce qui donne des résultats inattendus. La solution est soit d'englober l'expression par des parenthèses soit de modifier cette macro "Wait" pour que son paramètre "Delay" soit entouré de ces parenthèses à chaque fois qu'il doit être évalué.
Cette dernière solution est de loin la préférable :


Wait   MACRO   Delay   ; Déclaration de la macro et de son paramètre
LoopsSET( (Delay) /4)-1
Cycles  SET (Delay)//4  
REPTLoops/250; Correspond à 250 × 4 soit 1000 cycles d'horloge
 BasicDelay250
ENDR
BasicDelayLoops//250; Complété par le reste de la division par 250
IF  Cycles=3  ; Affinage
 JMP  $+1  ; Absorbe 3 cycles en une seule instruction
ELSE  
 REPTCycles  ; Répétition de NOP modulo 4
   NOP
 ENDR
ENDIF  
ENDM

Conjointement à cette correction, la macro a été modifiée pour économiser de la mémoire programme. Un test est maintenant effectué sur le nombre de cycles à ajuster et s'il est égal à 3, la répétition d'instructions "NOP" est remplacée par une seule instruction "JMP $+1" qui absorbe à elle seule 3 cycles à la fois.




Maintenant que la trame est constituée et qu'elle boucle indéfiniment sur elle-même, il reste plus qu'à gérer l'impulsion de synchronisation verticale sur le port RB1.
Pour que début et la fin de cette impulsion de synchronisation trame soit strictement synchrone avec celle de la synchronisation ligne, l'émission de cette dernière doit être modifiée pour que les deux changent d'état simultanément tout en respectant le temps d'exécution de 4 cycles précédemment évoqué : surlignage marron  .

;------------------------------ Impulsion de synchronisation trame --------------------------------


SyncField   SET   $
   ; Palier de suppression arrière (Back Porch), suite
:LoopCLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Blanking des lignes pendant la synchronisation trame
SetColor Black,2456+161-14  ; Contenu + palier avant forcés au niveau du noir pendant cette période. Moins les 14 cycles du décomptage
SyncFieldSET$; Décomptage des lignes du bloc en fin du palier (14 cycles)
NextLineSyncField,LaggingField,23; Durée de 23 lignes pour le blanking arrière
; Impulsion de synchronisation horizontale
:StartMOV  W,RB  ; Lecture du port RB, la manipulation de bits impossible sur W est réalisée sur son emplacement mémoire WREG
SETB  WREG.0  ; Positionnement du bit correspondant à la synchronisation horizontale
SETB  WREG.1  ; Positionnement  du bit correspondant à la synchronisation verticale
MOV  RB,W  ; Émission de ce nouvel état
Wait238; Durée de l'impulsion ligne, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPSyncField:Loop; Rebouclage avec absorption de 3 cycles

;----------------------------------------- Blanking arrière ---------------------------------------


LaggingField   SET   $
   ; Palier de suppression arrière (Back Porch), suite
:LoopCLRBSyncH; Effacement de l'impulsion de synchronisation Horizontale
Wait323; 323 cycles pour le palier arrière, tient compte des 4 cycles absorbés par les instructions précédentes
; Blanking des lignes à la suite de la synchronisation trame
SetColor Black,2456+161-14  ; Contenu + palier avant forcés au niveau du noir pendant cette période. Moins les 14 cycles du décomptage
LaggingFieldSET$; Décomptage des lignes du bloc en fin du palier (14 cycles)
NextLineLaggingField,PatternField,224; Durée de 224 lignes pour afficher la mire à barres colorées
; Impulsion de synchronisation horizontale
:StartMOV  W,RB  ; Lecture du port RB, la manipulation de bits impossible sur W est réalisée sur son emplacement mémoire WREG
SETB  WREG.0  ; Positionnement du bit correspondant à la synchronisation horizontale
CLRB  WREG.1  ; Effacement  du bit correspondant à la synchronisation verticale
MOV  RB,W  ; Émission de ce nouvel état
Wait238; Durée de l'impulsion ligne, tient compte des 4 cycles absorbés par les instructions précédentes
; Palier de suppression arrière (Back Porch)
JMPLaggingField:Loop; Rebouclage avec absorption de 3 cycles

La manipulation de bits, ceux correspondant aux synchronisations, est impossible sur l'accumulateur W, cependant ce registre peut être mappé en mémoire à la place d'un autre qui réside à l'adresse $01.
Deux conditions sont alors requises :

  • Avoir positionné le pseudo fusible OPTIONX qui sera programmé en même temps que le code dans le microcontrôleur SX28. Sinon le bit "RTW" du registre "OPTION" restera positionné à 1.
    Ceci s'effectue dans le texte source à l'aide de la directive "DEVICE  OPTIONX"
  • Que le bit "RTW" dans le registre "OPTION" soit à 0.
    Tous les bits ayant été positionnés à 1 suite au reset, il faut l'avoir préalablement effacé avec l'instruction "MOV  !option,#%0111111" lors de la séquence d'initialisation sinon on accède au compteur/temporisateur RTCC à la place.
L'accumulateur W est alors accessible en temps que registre mémoire "WREG" et ses bits peuvent être alors manipulés aisément.




Après nouvel assemblage du code source et programmation d'un SX28AC avec le programmateur Fluffy-2, voici les différents signaux échantillonnés à 10 MHz par le Scanalogic 2 pour une fréquence ligne de 15 kHz :
CH1/trace bleue pour la synchronisation horizontale.
CH2/trace jaune pour la synchronisation verticale.



Le temps mesuré entre deux impulsions de synchronisation trame avec la fonction "Quick time selection" est de 17,716 ms, le "Recommended Signal Timing Chart" inséré dans le premier post de ce wip donnait 16,715 ms, c'est tout bon compte tenu de toutes les imprécisions.

Le détail de l'impulsion trame, elle dure bien les trois lignes prévues :




Maintenant reste à intégrer la lecture des dip-switches pour pouvoir choisir la fréquence ligne de la mire...
Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard





gc339

#12
Citation de: nc333 le Mercredi 06 Février 2013, 20:53:47 PM
Je propose quelques améliorations :
_afficher le bord du quadrillage en une autre couleur, effectivement quand l'écran est très déréglé on ne peut savoir si l'image est décentrée de un ou deux carreaux

Oui, c'est facilement faisable dans le cas de la mire à quadrillage. Mais je pencherais plus pour un trait de cadre plus épais ou constitué d'un trait double.

Citation de: nc333 le Mercredi 06 Février 2013, 20:53:47 PM
_Garder une page blanche en plus, peut s'avérer utile pour mettre en évidence le marquage du tube ou pour régler la luminosité de la THT

Le marquage du cathoscope se voit plutôt quand il est éteint, la seule utilité que pourrait avoir une image uniformément blanche concerne plutôt le contrôle de l'efficacité de la démagnétisation

Citation de: nc333 le Mercredi 06 Février 2013, 20:53:47 PM
_ Faire un dégradé de chaque couleur, pour régler les cut-offs

Oui, j'ai déjà songé à inclure ce genre de mire :



Photo postée à l'origine par kaneda56 sur Néo-Arcadia

Cette mire nécessite 3 convertisseurs digital/analogique, un par couleur primaire, ce qui la complexifie. Mais pour l'instant ce n'est pas la priorité car j'ai surtout besoin d'un générateur simplifié.
Mais j'ai prévu d'utiliser les 8 ports RC0 à RC7 qui restent disponibles et de réaffecter les 4 ports RA0 à RA3 à cet effet. Cela fera 12 ports au total pour piloter 3 réseaux R2-R avec 16 niveaux par couleur, juste ce qu'il faut pour obtenir la mire de dégradés comme celle de la photo.

Citation de: nc333 le Mercredi 06 Février 2013, 20:53:47 PM
_Mettre le montage sur batterie
Qui dit batteries, dit chargeur. Et c'est encore une complication pour un générateur vidéo qui se veut le plus simple possible avec un minimum de composants.

Néanmoins, cette dernière proposition m'a fait réaliser qu'il vaudrait mieux que j'inclus le générateur dans un boîtier qui le protège.

Un boîtier Teko de récupération va vivre une nouvelle vie, le circuit imprimé d'origine a été conservé car il incluait une petite alimentation secteur et aussi parce qu'il facilitait la fixation de la plaquette pré-percée au-dessus avec uniquement des entretoises de 15 mm. Néanmoins une découpe a été effectuée dans ce circuit, juste en dessous de la plaque pré-percée, pour laisser le champ libre aux broches des supports à wrapper.



La découpe dans le circuit imprimé d'origine.
La plaque pré-percée vue coté mini-wrapping avec la fixation de l'embase HD-15 ainsi que celle du bloc de mini-switches qui permettront de choisir la mire.



La plaque prépercée en place sur ses entretoises.
A gauche le bloc de mini-switches, au centre l'embase vidéo HD-15 et à droite celle du secteur 220 VAC, il/elles sont tous accessibles sur le même face du boîtier.



La mire à barres colorée sur un Hantarex MTC9000, le commutateur SW4 du châssis a du être changé de position car la mire délivre des impulsions de synchronisation positives.
Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard





gc339

#13
Le timing des signaux à 15 kHz tel qu'il est donné à la page I-5 du "Service Manual" du moniteur MS-2931 :




Et les durées retenues pour le générateur de mire, en nombre de pas de 20 ns :



Timing ligne 15 kHz:   Timing Trame associé :


  • 161 pas ou µ-cycles pour le palier de suppression avant.
  • 238 pas pour l'impulsion de synchronisation horizontale.
  • 323 pas pour le palier de suppression arrière.
  • 2456 pas pour le contenu à afficher.


  • 13 lignes pour le champ de suppression avant.
  • 3 lignes pour l'impulsion de synchronisation verticale.
  • 23 lignes pour le champ de suppression arrière.
  • 224 lignes à afficher (au lieu de 381 ).

Rien à redire en ce qui concerne la trame, le nombre de 224 lignes affichées est divisible par 8 (28 × 8 ) et convient donc parfaitement.





Dans le timing trame des signaux à 24 kHz (moitié supérieure de la page I-6 du "Service Manual" du moniteur MS-2931 ), le nombre de lignes constituant l'image est égal à 381, nombre impair indivisible par 8 :




Par contre dans le même timing à 24 kHz donné page 15/21 dans le "Service Manual" du moniteur du moniteur Nanao MS9-29SU le nombre de lignes affichées est de 384, nombre beaucoup plus pertinant puisque divisible par 8 (48 × 8 ).




A durée de ligne égale (41 µs ) et durée de trame identique (17,384 ms ou 424 lignes ) ce nombre de lignes affichées supérieur est effectué au détriment du champ de suppression arrière qui de 28 lignes rétrograde à 25 lignes, toutes les autres durées élémentaires de la trame restant inchangées.

Ce nombre de 384 lignes affichées par trame, est celui qui sera donc retenu pour les timings des signaux à 24 kHz que la mire la mire devra générer, ainsi :


Timing ligne 24 kHz :   Timing Trame correspondant :


  • 142 pas ou µ-cycles pour le palier de suppression avant.
  • 150 pas pour l'impulsion de synchronisation horizontale.
  • 222 pas pour le palier de suppression arrière.
  • 1536 pas pour le contenu à afficher.


  • 11 lignes pour le champ de suppression avant.
  • 4 lignes pour l'impulsion de synchronisation verticale.
  • 25 lignes (au lieu de 28 ) pour le champ de suppression arrière.
  • 384 lignes à afficher (au lieu de 381 ).





Par contre il y a un souci avec les timings des signaux à 31 kHz ou plus exactement à 31,67 kHz, ceux déjà évoqués et qui sont donnés à la page I-6 du "Service Manual" du moniteur MS-2931 :




En effet, le palier de suppression avant de 0,33 µs calculé puis arrondi à 17 pas est trop court par rapport aux 14 cycles absorbés par la macro de comptage de lignes auxquels il faut encore ajouter 4 cycles supplémentaires pour l'émission de l'impulsion ligne.
De plus le nombre de 477 lignes affichées dans une trame est impair, ce qui le disqualifie d'entrée.

Il y a bien les timings à 31,69kHz donnés page 1-10 dans le "Service Manual" du moniteur Nanao MS2934 mais ils sont inexploitables car les chiffres sont illisibles :




Heureusement, dans cette même notice, un tableau page 2-6 énumère toutes les informations qui étaient illisibles :




Il reste donc 31,55 - (3,04 + 3,22 + 23,70) soit 1,59 µs pour le palier de suppression avant, ce qui en arrondissant correspond à 80 pas ou µ-cycles, ce qui est beaucoup plus confortable que les 17 pas extrapolés du timing précédent. Non seulement, le nombre de lignes affichées par trame est divisible par 8 (80 × 8 ), mais il correspond à celui du standard VGA.

Ce sont aussi les mêmes timings, à 10 ns près en ce qui concerne la ligne, qui sont donnés page 5 dans le "Service Manual" du moniteur Sanwa 29E31S, ce qui les rend encore plus plausibles :




Même avec les données du dernier graphique qui sont toutes des nombres pairs, il va falloir procéder à un ajustage car le nombre de 1185 pas (23700 ÷ 20 ) alloués à la période affichée dans chaque ligne n'est pas divisible par 8. Le nombre le plus proche étant 1184 (148 × 8 ), le palier de suppression qui est le plus court des 4 autres intervalles de temps, se doit d'être gratifié d'un pas supplémentaire pour compenser, on a donc :


Timing ligne 31 kHz :   Timing Trame correspondant :


  • 81 pas ou µ-cycles pour le palier de suppression avant (au lieu des 17 précédents ).
  • 152 pas  pour l'impulsion de synchronisation horizontale.
  • 161 pas pour le palier de suppression arrière.
  • 1184 pas pour le contenu à afficher.


  • 14 lignes pour le champ de suppression avant.
  • 3 lignes pour l'impulsion de synchronisation verticale.
  • 33 lignes pour le champ de suppression arrière.
  • 480 lignes à afficher (au lieu des 477 précédentes ).





Le câblage des dip-switches :




Le bloc de dip-switches est raccordé directement sur les entrées RB4 à RB7 qu'ils connectent à la masse quand le switch correspondant est positionné sur "ON". Ainsi pour que l'entrée soit lue à l'état "1" quand son switch associé est positionné sur "OFF", il faut avoir préalablement validé les résistances de "pull-up" internes au micro-contrôleur. Il n'est pas nécessaire de valider ces résistances en permanence si l'on veut faire de petites économie de consommation, il suffit de les valider quelques cycles avant la lecture pour qu'elle soit fiable et de les inhiber immédiatement après.

;------------------------ INITIALIZATION ROUTINE -----------------------


   ORG   8
Initializemovra,#%0000; Set port A low
movrb,#%11111111; Set port B high
movrc,#%11111111; Set port C high
; Pull-Up Resistor Configuration
modePLP; Allow Pull-Up Resistor configuration
mov!ra,#%1111; Set port A, bit 0-3 to normal
mov!rb,#%00001111; Set port B bits 4-7 with pull-up resistors
mov!rc,#%11111111; Set port C bits 0-7 to normal
; Port Direction Configuration
modeTRIS; Allow Direction configuration
mov!ra,#%0000; Set port A bits 0-3 to output
mov!rb,#%11110000; Set port B bits 0-3 to output, 4-7 to input
mov!rc,#%11111111; Set port C bits 0-7 to input

Les registres notifiés !RA, !RB et !RC (avec le point d'exclamation ) ne sont pas des registres mais des points d'accès au bloc de registres qui contrôlent les ports RA, RB et RC. Il est nécessaire de définir préalablement le registre que l'on veut atteindre dans le bloc en écrivant sa sous-adresse dans le registre "MODE" commun à tous grâce à l'instruction du même nom.





Maintenant que les paramètres des signaux à 15, 24 et 31 kHz ont été retouchés, que les dip-switches sont câblés, il ne reste plus qu'à écrire et tester le bout de programme qui permettra de choisir la bonne fréquence de la mire à barre colorées à la mise sous tension du générateur.
Plus tard cette lecture des dip-switches pourra être effectuée à chaque trame ou toutes les X trames afin de pouvoir changer de mire et de fréquence au fil de l'eau sans avoir à réinitialiser le microcontrôleur à chaque changement.
Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard





gc339

#14
Citation de: gc339 le Lundi 18 Février 2013, 17:07:38 PMMaintenant que les paramètres des signaux à 15, 24 et 31 kHz ont été retouchés, que les dip-switches sont câblés, il ne reste plus qu'à écrire et tester le bout de programme qui permettra de choisir la bonne fréquence de la mire à barre colorées à la mise sous tension du générateur.
Plus tard cette lecture des dip-switches pourra être effectuée à chaque trame ou toutes les X trames afin de pouvoir changer de mire et de fréquence au fil de l'eau sans avoir à réinitialiser le microcontrôleur à chaque changement.

Comme la mémoire programme du µC est paginée, 4 pages de 512 octets, et que le code du générateur dépasse allègrement cette limitation de page, il va falloir gérer la pagination de cette mémoire programme.
Le plus simple est donc de réserver la page 0 aux initialisations et aux tests qui seront effectués dans la boucle principale et d'affecter chacune des trois pages restantes à l'exécution des boucles locales propres à chaque fréquence ligne :

  • Chaque boucle locale génèrera les mires pour une fréquence ligne donnée, ainsi les pages 1, 2 et 3 hébergeront respectivement les boucles locales pour les fréquences 15, 24 et 31 kHz.
  • L'exécution sera transférée en fin de chaque trame à la boucle principale qui lira alors les micro-switches.
  • Le contrôle passera de la boucle principale à la boucle locale désignée par ces micro-switches. S'il sont inchangés, le déroulement reprendra dans la même boucle locale là où il a été dérouté.
Ainsi les micro-switches seront lus périodiquement et la fréquence ligne de la mire pourra être modifiée au fil de l'eau sans avoir à reseter le µC ou à couper son alimentation.




Edition du 25/09/2015 : 1536 est la valeur correcte pour le 24 kHz.

Rappel des timings choisis :








Line
Frequ.

(kHz)
   |
|
|
   Front
Porch

(µcycles)
   Horiz.
Synch.

(µcycles)
   Back
Porch

(cycles)
   Display

(µcycles)
   |
|
|
   Leading
Blank

(lines)
   Vert.
Synch.

(lines)
   Lagging
Blank

(lines)
   Pattern

(lines)
15 | 161 238 323 2456   | 13 3 23 224
24 | 142 150 222 13361536   | 11 4 25 384
31 | 81 152 161 1184   | 14 3 33 480




Les déclarations en tête du programme :

Citation






;-------------------------- DEVICE DIRECTIVES --------------------------

                                                                                                
IFDEF__SASM;SASM Directives
DEVICESX28AC, OSCHS3, TURBO, BOROFF, SYNC, OPTIONX, CARRYX
IRC_CALIRC_SLOW
ELSE; Parallax Assembler Directives
DEVICESX28AC, OSCXT2, TURBO, BOROFF, SYNC
ENDIF
ID"PATGEN"
RESETInitialize; Reset vector

;------------------------------- EQUATES -------------------------------

                                                                                                
SyncHEQUrb.0; Synchro Horizontale sur RB0
SyncVEQUrb.1; Synchro Verticale sur RB1
BlackEQU%0000
BlueEQU%0001; Bit 2°
RedEQU%0010; Bit 2¹
GreenEQU%0100; Bit 2²
CyanEQUGreen + Blue
MagentaEQURed + Blue
YellowEQURed + Green
WhiteEQURed + Green + Blue


                        ; MODE Register Settings to access the port control registers

TRISEQU$0F; Data Direction Register
PLPEQU$0E; Pull-Up Resistor Enable Register
LVLEQU$0D; TTL/CMOS Select Register
STEQU$0C; Schmitt Trigger Enable Register
WKENEQU$0B; Wake Up Enable Register
WKEDEQU$0A; Wake Up Edge Select Register
WKPNDEQU$09; MIWU Pending Register
CMPEQU$08; Comparator Enable Register
                                                                                                
;------------------------------ VARIABLES ------------------------------

                                                                                                
ORG8; Début de mémoire vive utilisable pour stocker les variables du progranne
LoopCounterDS1; Step Counter
LineCounterDS2; Line Conter
FrameCounterDS1; Frame Counter
FlipFlopDS1; Used to blink pattern


Juste la déclaration d'une nouvelle variable "FlipFlop" qui sera utile pour la mire clignotante




La déclaration des macros :

Citation






;-------------------------------- MACRO's -------------------------------

                                                                                                
BasicDelayMACROValue; Absorbe un nombre de µcycles = (Value × 4)
LOCALLocLoop; Etiquette interne à la macro
movLoopCounter,#Value; 2 µC, initialisation du compteur de bouclettes
LocLoopDJNZLoopCounter,LocLoop; 4 µC sinon 2 en sortie de boucle
ENDM

DelayMACROValue,Offset; Temporisation incluant une franchise (Offset)
LoopsSET(Value-(Offset))/4
CyclesSET(Value-(Offset))//4
REPTLoops/250; Correspond à 250×4 soit 1000 µcycles d'horloge
 BasicDelay250
ENDR
BasicDelayLoops//250; Complété par le reste de la division par 250
IFCycles=3; Afinage
 jmp$+1; Absorbe 3 µcycles en une seule instruction
ELSE
 REPTCycles; Répétition de NOP modulo 4
   nop
 ENDR
ENDIF
ENDM

WaitMACROValue; Temporisation, inclue les 4 µcycles du bloc d'instructions qui la précéde
 DelayValue,4; Minoration des 4 µcycles
ENDM

SetColorMACROColor, Delay; Emission de la couleur (Color), durée = (Delay)
movw,ra; 1 µC, lecture du port RA
andw,#%1000; 1 µC, effacement des 3 bits de couleur
orw,#Color; 1 µC, positionnement des bits impactés
movra,w; 1 µC, émission de cette nouvelle couleur
waitDelay; Temporisation, tient compte des µcycles absorbés par les instructions précédentes
ENDM

ColorBarsMACRODelayBar; Emission des 8 barres colorées, durée de chaque barre = (DelayBar)
SetColorWhite,DelayBar; Première barre verticale
SetColorYellow,DelayBar
SetColorCyan,DelayBar
SetColorGreen,DelayBar
SetColorMagenta,DelayBar
SetColorRed,DelayBar
SetColorBlue,DelayBar
SetColorBlack,DelayBar; La huitième barre est aussi la dernière
ENDM

NextLineMACROCurrent,Next; Absorbe 14 µCycles sauf sortie vers MainLoop qui en absorbe que 9
LOCALLocLab1,LocLab2; Déclaration des étiquettes privées
djnzLineCounter, LocLab1; 4/2 µC, décomptage sur octet de poids faible
testLineCounter+1; 1 µC, test de nullité sur l'octet de poids fort
NextAddrSETNext
IFNextAddr=MainLoop
 jnzLocLab2; 4/2 µC
 jmp@MainLoop; 1+3 µC, soit 9 consommés au total
ELSE
 jzNext??:SetUp; 4/2 µC, 7 déjà consommés, les 7 manquants seront absorbés par le setup
 skip; 2 µC, 7 déjà consommés, encore 7 à absorber
ENDIF
LocLab1jmp$+3; 3 µC, 7 déjà consommés, encore 7 à absorber
LocLab2decLineCounter+1; 1 µC, décomptage propagé sur octet de poids fort
skip; 2 µC, 10 déjà consommés, encore 4 à absorber
jmp$+1; 3 µC, 10 déjà consommés, plus que 4 à absorber
nop; 1 µC, 11 déjà consommés, plus que 3 à absorber
jmpCurrent??:Start; 3 µC, 14 consommés au total
ENDM

PresetCountMACROValue; Initialisation du compteur ligne, absorbe 4 µCycles
movLineCounter,#(Value//256); 2 µC, chargement du compteur, octet de poids faible
movLineCounter+1,#(Value/256); 2 µC, idem, octet de poids fort
ENDM



  • Eclatement de l'ancienne macro "Wait" avec création de la macro fille "Delay" issue de cette première :

    • La macro "Wait" nouvelle mouture génère le même délai que l'ancienne en appelant la nouvelle macro "Delay".
    • La nouvelle macro "Delay" génère une temporisation ± un offset passé comme deuxième paramètre.
  • Modifications de la macro "NextLine :

    • Suppression du troisième paramètre et extraction des instructions correspondantes. L'opération de chargement du compteur ligne est transféré à la nouvelle macro "PresetCount".
    • Ajout d'une condition, l'adresse "Next" passée en deuxième paramètre est comparée avec celle de la boucle principale. Si c'est bien l'adresse de cette boucle principale, le programme sera dérouté vers le test des micro-switches de la boucle principale plutôt que de poursuivre son déroulement normal dans la boucle locale.
  • Création de la macro "PresetCount" issue de l'ancienne macro "NextLine".




Le programme principal en page 0 (adresse 0000H) :

Citation






                                                
LISTF=INHX8M

;-------------------------- ROUTINE D'INTERRUPTION --------------------------

                                                                                                
ORG0
Interruptreti

;-------------------------- ROUTINE D'INITIALISATION -------------------------

                                                                                                
ORG8
Initializemovra,#%0000; Set port A low
movrb,#%11111111; Set port B high
movrc,#%11111111; Set port C high


                        ; Pull-Up Resistor Configuration

modePLP; Allow Pull-Up Resistor configuration
mov!ra,#%1111; Set port A, bit 0-3 to normal
mov!rb,#%00001111; Set port B bits 4-7 with pull-up resistors
mov!rc,#%00000000; Set port C bits 0-7 with pull-up resistors
                                                                                                

                        ; Port Direction Configuration

modeTRIS; Allow Direction configuration
mov!ra,#%0000; Set port A bits 0-3 to output
mov!rb,#%11110000; Set port B bits 0-3 to output, 4-7 to input
mov!rc,#%11111111; Set port C bits 0-7 to input
                                                                                                

                        ; Device Configuration Options

mov!option,#%01111111; Raz bit RTW, RTCC inhibé, WREG accessible à la place
                                                                                                
;---------------------------- PROGRAMME PRINCIPAL -----------------------------

                                                                                                
MainsetbSyncH
setbSyncV
clrFlipFlop; Initialisation du flip flop
jmpPresetFrCnt


                        ; Compteur de trames pour clignotement, absorbe 7 µCycles

MainLoopdjnzFrameCounter,NoPreset; 2/4 µC
notFlipFlop; 1 µC, inversion du flip flop
PresetFrCntmovFrameCounter,#30; 2 µC, clignotement toutes les 30 trames (½ seconde)
skip; 2 µC, ajustement à 7 µC si rechargement FrameCount
NoPresetjmp$+1; 3 µC, ajustement à 7 µCycles pour décomptage normal
                                                                                                

                        ; Lecture de la fréquence ligne sur les 2 premiers microswitches.
; Absorbe 11 µCycles quelque soit la boucle à exécuter.

jnbrb.5,Jmp31k; 2/4 µC, lecture de la fréquence programmée par les dip-switches
jnbrb.4,Jmp24k; 2/4 µC
Jmp15kjmp$+1; 3 µC pour ajustage absorpsion à 11 µC
jmp@Start15k; 1+3 µC, instruction de page incluse avec "@"
Jmp24knop; 1 µC pour ajustage absorpsion à 11 µC
jmp@Start24k; 1+3 µC, instruction de page incluse avec "@"
Jmp31kjmp$+1; 3 µC pour ajustage absorpsion à 11 µC
jmp@Start31k; 1+3 µC, instruction de page incluse avec "@"
                                                                                                

Ajout des tests :

  • Sur le compteur trame. La variable "FlipFlop" est inversée toutes les trente trames, donc la mire concernée clignotera toutes les ½ secondes environ.
  • Sur les deux premiers micro-switches. L'exécution du programme continuera dans la boucle locale (la page de 512 octets) correspondant à la fréquence ligne programmée.




Il y a donc 3 boucles locales, une pour chaque fréquence ligne.

Chaque boucle locale correspond à une trame, elle est composée de 4 blocs dont chacun est constitué de la répétition d'un nombre fixe de lignes dépendant de la fréquence ligne utilisée :

  • L'impulsion de synchronisation trame. Le signal correspondant est à zéro pendant cette période.
  • Le champ à la suite de l'impulsion trame, le signal vidéo est au niveau du noir pendant cette période.
  • Les lignes affichant la mire, les couleurs de la mire sont affichées pendant cette période.
  • Le champ précédant l'impulsion trame, le signal vidéo est au niveau du noir pendant cette période.
C'est en fin d'exécution de ce dernier bloc, c'est à dire à la fin de la trame, que le contrôle est transféré de la boucle locale vers la boucle principale pour incrémenter le compteur de trame et lire la fréquence ligne programmée sur les micro-switches.

Chaque ligne à l'intérieur d'un bloc est décomposée en 4 périodes distinctes dépendantes de la fréquence utilisée :

  • L'impulsion de synchronisation ligne. Le signal correspondant est à zéro pendant cette période.
  • Le palier arrière (back porch), le signal vidéo est au niveau du noir pendant ce palier.
  • Le contenu de la ligne, il est affiché uniquement pendant cette période.
  • Le palier avant (front porch), le signal vidéo est au niveau du noir pendant ce palier.
C'est en fin de ce dernier palier que le compteur ligne est décrémenté, le déroulement du bloc correspondant à un champ de la trame est terminée quand ce compteur ligne s'annule, l'exécution est alors transférée dans le bloc suivant.

Le code des 3 pages est identique aux noms des étiquettes près, il n'y a que les valeurs des paramètres (nombre de µcycles, nombre de lignes) passées aux macros qui diffèrent :




Le programme générant les mires à 15 kHz en page 1 (adresse 0200H)

Citation






                                                
ORG$0200
Start15kEQU$

;****************************** Impulsion de synchronisation trame ******************************

                                                                                                
SyncHor15kSET$
:SetUpPresetCount3; Nombre de lignes allouées à l'impulsion de synchronisation verticale
jmpSyncHor15k:Start


                        ; Palier de suppression arrière (Back Porch), suite

SyncHor15kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait323; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes tout pendant la durée de l'impulsion de synchronisation trame

SetColorBlack,2456+161-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineSyncHor15k,Lagging15k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

SyncHor15kSET$
:Startmovw,rb; 1 µC, lecture du port RB, manipulation de bits sur W à partir de WREG
clrbwreg.0; 1 µC, positionnement du bit affecté à la synchronisation horizontale
clrbwreg.1; 1 µC, positionnement du bit affecté à la synchronisation verticale
movrb,w; 1 µC, émission de cette nouvel état
Wait238; Durée de l'impulsion ligne
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpSyncHor15k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;********** Champ à la suite de l'impulsion de synchronisation trame ( blanking arrière) **********

                                                                                                
Lagging15kSET$
:SetUpPresetCount23; Nombre de lignes allouées au blanking arrière
jmpLagging15k:Start


                        ; Palier de suppression arrière(Back Porch),suite

Lagging15kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait323; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes à la suite de l'impulsion de synchronisation trame

SetColorBlack,2456+161-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineLagging15k,Pattern15k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

Lagging15kSET$
:Startmovw,rb; 1 µC, lecture du port RB, manipulation de bits sur W à partir de WREG
clrbwreg.0; 1 µC, positionnement du bit affecté à la synchronisation horizontale
setbwreg.1; 1 µC, effacement du bit affecté à la synchronisation verticale
movrb,w; 1 µC, émission de cet nouvel état
Wait238; Durée de l'impulsion ligne
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpLagging15k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;****************************** Affichage du motif de la mire ******************************

                                                                                                
Pattern15kSET$
:SetUpPresetCount224; 224 Nombre de lignes allouées pour afficher la mire
jmpPattern15k:Start


                        ; Palier de suppression arrière (Back Porch), suite

Pattern15kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait323; Durée du palier arrière
                                                                                                

                        ; Affichage des 8 barres colorées de la mire

ColorBars307; Chaque barre occupe 307 µcycles
                                                                                                

                        ; Palier de suppression avant (Front Porch)

SetColorBlack,161-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLinePattern15k,Leading15k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

Pattern15kSET$
:Startjmp$+1; Absorption de 3 µcycles
clrbSyncH; Emission de l'impulsion SyncH
Wait238; Durée de l'impulsion
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpPattern15k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;************** Champ précédant l'impulsion de synchronisation trame (blanking avant) **************

                                                                                                
Leading15kSET$
:SetUpPresetCount13; 4 µC, nombre de lignes allouées au blanking avant
jmpLeading15k:Start; 3 µCycles


                        ; Palier de suppression arrière (Back Porch), suite

Leading15kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait323; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes précédant l'impulsion de synchronisation trame
; Le nombre de µcycles doit être minoré de 34 pour lire les micro-switches lors du rebouclage par MainLoop
; 34 µcycles = 9 (NextLine) + 18 (MainLoop) + 7 (SyncHor××k:SetUp)

SetColorBlack,2456+161-34; Contenu = niveau du noir + palier avant, minoré de 34 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineLeading15k,MainLoop; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale
; Un délai supplémentaire de 20 µCycles (34-14) doit être inséré car le test du compteur n'en a consommé que 14

Leading15kSET$
:StartDelay20,-3; Délai majoré de 3 µcycles pour remplacer le conventionnel "jmp $+1"
clrbSyncH; Emission de l'impulsion SyncH
Wait238; Durée de l'impulsion
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpLeading15k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                




Le programme générant les mires à 24 kHz en page 2 (adresse 0400H)

Citation






                                                
ORG$0400
Start24kEQU$

;****************************** Impulsion de synchronisation trame ******************************

                                                                                                
SyncHor24kSET$
:SetUpPresetCount4; Nombre de lignes allouées à l'impulsion de synchronisation verticale
jmpSyncHor24k:Start


                        ; Palier de suppression arrière (Back Porch), suite

SyncHor24kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait222; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes tout pendant la durée de l'impulsion de synchronisation trame

SetColorBlack,1536+142-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineSyncHor24k,Lagging24k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

SyncHor24kSET$
:Startmovw,rb; 1 µC, lecture du port RB, manipulation de bits sur W à partir de WREG
clrbwreg.0; 1 µC, positionnement du bit affecté à la synchronisation horizontale
clrbwreg.1; 1 µC, positionnement du bit affecté à la synchronisation verticale
movrb,w; 1 µC, émission de cette nouvel état
Wait150; Durée de l'impulsion ligne
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpSyncHor24k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;********** Champ à la suite de l'impulsion de synchronisation trame ( blanking arrière) **********

                                                                                                
Lagging24kSET$
:SetUpPresetCount25; Nombre de lignes allouées au blanking arrière
jmpLagging24k:Start


                        ; Palier de suppression arrière(Back Porch),suite

Lagging24kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait222; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes à la suite de l'impulsion de synchronisation trame

SetColorBlack,1536+142-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineLagging24k,Pattern24k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

Lagging24kSET$
:Startmovw,rb; 1 µC, lecture du port RB, manipulation de bits sur W à partir de WREG
clrbwreg.0; 1 µC, positionnement du bit affecté à la synchronisation horizontale
setbwreg.1; 1 µC, effacement du bit affecté à la synchronisation verticale
movrb,w; 1 µC, émission de cet nouvel état
Wait150; Durée de l'impulsion ligne
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpLagging24k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;****************************** Affichage du motif de la mire ******************************

                                                                                                
Pattern24kSET$
:SetUpPresetCount384; Nombre de lignes allouées pour afficher la mire
jmpPattern24k:Start


                        ; Palier de suppression arrière (Back Porch), suite

Pattern24kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait222; Durée du palier arrière
                                                                                                

                        ; Affichage des 8 barres colorées de la mire

ColorBars1536/8; Chaque barre occupe 192 µcycles
                                                                                                

                        ; Palier de suppression avant (Front Porch)

SetColorBlack,142-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLinePattern24k,Leading24k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

Pattern24kSET$
:Startjmp$+1; Absorption de 3 µcycles
clrbSyncH; Emission de l'impulsion SyncH
Wait150; Durée de l'impulsion
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpPattern24k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;************** Champ précédant l'impulsion de synchronisation trame (blanking avant) **************

                                                                                                
Leading24kSET$
:SetUpPresetCount11; Nombre de lignes allouées au blanking avant
jmpLeading24k:Start


                        ; Palier de suppression arrière (Back Porch), suite

Leading24kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait222; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes précédant l'impulsion de synchronisation trame
; Le nombre de µcycles doit être minoré de 34 pour lire les micro-switches lors du rebouclage par MainLoop
; 34 µcycles = 9 (NextLine) + 18 (MainLoop) + 7 (SyncHor××k:SetUp)

SetColorBlack,1536+142-34; Contenu = niveau du noir + palier avant, minoré de 34 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineLeading24k,MainLoop; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale
; Un délai supplémentaire de 20 µCycles (34-14) doit être inséré car le test du compteur n'en a consommé que 14

Leading24kSET$
:StartDelay20,-3; Délai majoré de 3 µcycles pour remplacer le conventionnel "jmp $+1"
clrbSyncH; Emission de l'impulsion SyncH
Wait150; Durée de l'impulsion
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpLeading24k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                




Le programme générant les mires à 31 kHz en page 3 (adresse 0600H)

Citation






                                                
ORG$0600
Start31kEQU$

;****************************** Impulsion de synchronisation trame ******************************

                                                                                                
SyncHor31kSET$
:SetUpPresetCount3; Nombre de lignes allouées à l'impulsion de synchronisation verticale
jmpSyncHor31k:Start


                        ; Palier de suppression arrière (Back Porch), suite

SyncHor31kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait161; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes tout pendant la durée de l'impulsion de synchronisation trame

SetColorBlack,1184+81-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineSyncHor31k,Lagging31k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

SyncHor31kSET$
:Startmovw,rb; 1 µC, lecture du port RB, manipulation de bits sur W à partir de WREG
clrbwreg.0; 1 µC, positionnement du bit affecté à la synchronisation horizontale
clrbwreg.1; 1 µC, positionnement du bit affecté à la synchronisation verticale
movrb,w; 1 µC, émission de cette nouvel état
Wait152; Durée de l'impulsion ligne
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpSyncHor31k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;********** Champ à la suite de l'impulsion de synchronisation trame ( blanking arrière) **********

                                                                                                
Lagging31kSET$
:SetUpPresetCount33; Nombre de lignes allouées au blanking arrière
jmpLagging31k:Start


                        ; Palier de suppression arrière(Back Porch),suite

Lagging31kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait161; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes à la suite de l'impulsion de synchronisation trame

SetColorBlack,1184+81-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineLagging31k,Pattern31k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

Lagging31kSET$
:Startmovw,rb; 1 µC, lecture du port RB, manipulation de bits sur W à partir de WREG
clrbwreg.0; 1 µC, positionnement du bit affecté à la synchronisation horizontale
setbwreg.1; 1 µC, effacement du bit affecté à la synchronisation verticale
movrb,w; 1 µC, émission de cet nouvel état
Wait152; Durée de l'impulsion ligne
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpLagging31k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;****************************** Affichage du motif de la mire ******************************

                                                                                                
Pattern31kSET$
:SetUpPresetCount480; Nombre de lignes allouées pour afficher la mire
jmpPattern31k:Start


                        ; Palier de suppression arrière (Back Porch), suite

Pattern31kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait161; Durée du palier arrière
                                                                                                

                        ; Affichage des 8 barres colorées de la mire

ColorBars1184/8; Chaque barre occupe 148 µcycles
                                                                                                

                        ; Palier de suppression avant (Front Porch)

SetColorBlack,81-14; Contenu = niveau du noir + palier avant, minoré de 14 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLinePattern31k,Leading31k; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale

Pattern31kSET$
:Startjmp$+1; Absorption de 3 µcycles
clrbSyncH; Emission de l'impulsion SyncH
Wait152; Durée de l'impulsion
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpPattern31k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
;************** Champ précédant l'impulsion de synchronisation trame (blanking avant) **************

                                                                                                
Leading31kSET$
:SetUpPresetCount14; Nombre de lignes allouées au blanking avant
jmpLeading31k:Start


                        ; Palier de suppression arrière (Back Porch), suite

Leading31kSET$
:LoopsetbSyncH; Effacement de l'impulsion de synchronisation horizontale
Wait161; Durée du palier arrière
                                                                                                

                        ; Blanking des lignes précédant l'impulsion de synchronisation trame
; Le nombre de µcycles doit être minoré de 34 pour lire les micro-switches lors du rebouclage par MainLoop
; 34 µcycles = 9 (NextLine) + 18 (MainLoop) + 7 (SyncHor××k:SetUp)

SetColorBlack,1184+81-34; Contenu = niveau du noir + palier avant, minoré de 34 µcycles
                                                                                                

                        ; Décomptage des lignes du bloc en fin du palier de suppression avant (14 µcycles)

NextLineLeading31k,MainLoop; Décomptage lignes et test si zéro
                                                                                                

                        ; Impulsion de synchronisation horizontale
; Un délai supplémentaire de 20 µCycles (34-14) doit être inséré car le test du compteur n'en a consommé que 14

Leading31kSET$
:StartDelay20,-3; Délai majoré de 3 µcycles pour remplacer le conventionnel "jmp $+1"
clrbSyncH; Emission de l'impulsion SyncH
Wait152; Durée de l'impulsion
                                                                                                

                        ; Palier de suppression arrière (Back Porch)

jmpLeading31k:Loop; Rebouclage avec absorption de 3 µcycles
                                                                                                
END




Pour l'instant le générateur ne délivre qu'un seul type de mire : celle à barre colorée, la prochaine étape sera l'inclusion de l'une ou l'autre de ces mires clignotantes dans chaque boucle locale.




   
Le repos, c'est fait pour les jeunes. Ils ont toute la vie devant eux. J. Gabin/M. Audiard





AsPiC

Merci gc339 pour ton boulot sur ce générateur de mire qui s'annonce indispensable ^-^