Je travaille sur un circuit numérique utilisant des composants discrets pour piloter un écran VGA 640x480 en mode texte 80x30.
Pour un affichage 640x480, l'horloge pixel est de 25,175 MHz, qui a une période d'environ 40 ns. Je ne comprends pas comment je suis censé pouvoir fournir un nouveau pixel à l'affichage aussi souvent.
L'architecture de base de mon circuit est la suivante:
Le compteur binaire pour les pixels horizontaux compte de 25,175 MHz à 800 (640 pixels visibles + 160 pour le porche avant, la synchronisation, le porche arrière). À 800, incrémenter le compteur de lignes verticales (et réinitialiser à 525 lignes)
En utilisant la position horizontale et verticale, dérivez les coordonnées x, y du caractère actuel.
En utilisant les coordonnées x, y du caractère, indexez dans la mémoire vidéo pour récupérer le caractère ASCII.
Utilisez le caractère ASCII pour indexer dans la ROM de caractères pour obtenir le modèle de bits pour le caractère
Utilisez un registre à décalage parallèle à série pour convertir une ligne de caractères de 8 pixels en bits individuels à une fréquence d'horloge de pixels
Si vous suivez la chaîne, cela va: Compteur -> RAM -> ROM -> Parallel to Serial Shift Register
En utilisant les composants les plus rapides que je puisse trouver, les délais de propagation et le temps d'accès totalisent environ 15 ns + 20 ns + 70 ns + 15 ns = 120 ns, bien plus que la période de 40 ns pour 25 MHz.
À des résolutions et des taux de rafraîchissement encore plus élevés, vous pouvez avoir des horloges de pixels bien au-dessus de 100 MHz, ce qui représente une période de 10 ns.
Comment est-il possible de fournir de nouveaux pixels à l'affichage toutes les 10 ns alors que le temps d'accès à la RAM / ROM est déjà bien supérieur, sans même prendre en compte tous les autres signaux de votre système?
la source
Réponses:
Il y a deux raisons principales pour lesquelles vous trouvez cela difficile.
Tout d'abord, vous utilisez des pièces plus anciennes et plus discrètes (intégration à plus petite échelle) que celles qui auraient été utilisées à cette époque à l'ère du VGA.
Mais ensuite, vous les utilisez de manière atypique. Plus précisément, votre approche n'est pas
pipelined
ce qui signifie que vous devez additionner plusieurs retards pour déterminer votre intervalle, et donc votre taux.En revanche, les conceptions numériques synchrones qui tentent d'atteindre la vitesse essaient d'en faire le moins possible entre les registres.
Bien que les détails diffèrent probablement un peu, grossièrement, cela fonctionnerait comme ceci:
Lorsque vous décomposez une tâche comme celle-ci, vous n'obtenez qu'un seul délai combinatoire plus un certain délai de propagation et enregistrez les temps de configuration et de maintien devant s'adapter entre les horloges.
Une conception construite de cette façon nécessitera de nombreuses horloges pour produire une sortie - la latence sera en fait plus élevée qu'une conception purement combinatoire. Mais il produit une nouvelle sortie correcte à chaque cycle d'une horloge beaucoup plus rapide.
Et bon, c'est de la vidéo, cela n'a pas vraiment d'importance si le CRT dessine une douzaine de pixels derrière le compteur de pixels - vous en tenez bien sûr compte dans le timing des signaux de synchronisation afin qu'ils soient corrects par rapport au moment où les données réellement sort du CAD.
Dans la pratique, presque tous les systèmes numériques complexes fonctionnent de cette façon, car c'est une excellente idée - jusqu'à ce qu'un processeur pipeliné atteigne une dépendance par rapport à un résultat de calcul antérieur ou à une branche conditionnelle ... Ensuite, les choses deviennent intéressantes, comme ils en parleraient dans la prochaine conférence d'une classe de systèmes numériques - mais heureusement, votre situation VGA est beaucoup plus simple, surtout si vous ne vous inquiétez pas encore des effets de déchirement si le tampon de caractères change pendant que l'écran est en cours de dessin.
En pratique, si vous voulez construire cela, faites-le dans un FPGA. Cela vous imposera des mémoires synchrones si vous utilisez des mémoires internes ou des registres d'E / S synchrones si vous utilisez de la mémoire externe. Vous obtiendrez beaucoup de coup de pouce vers une conception appropriée, le tissu lui-même sera plus rapide que vos pièces discrètes, et bien sûr, si vous faites une erreur, vous n'avez qu'à tourner les pouces pendant qu'il recompile plutôt que de passer une longue journée à recâbler .
la source
Vous oubliez qu'un adaptateur graphique ne dessinerait jamais qu'un seul pixel, mais au moins une ligne de balayage complète. Ainsi, ce serait un problème complètement pipelineable.
N'oubliez pas non plus qu'il y a déjà eu cinq décennies de matériel de production vidéo. Votre problème serait généralement résolu avec un type spécial de RAM, dans lequel vous restituez vos lettres sur un port, et qui est lu séquentiellement sur un signal vidéo DAC. Ce matériel est bien plus rapide que ce que vous regardez.
Non, pourquoi feriez-vous ça? Vous mettriez simplement votre pixel de ligne dans une zone de mémoire contiguë et le mettriez linéairement sur votre DAC - s'il s'agit d'une implémentation CPU / MCU, vous ne laisseriez même pas votre CPU faire cela, mais une unité DMA, programmée pour ne rien faire mais prendre une valeur après l'autre et la mettre par exemple sur un port de données parallèle, sans aucune interaction avec le cœur du processeur.
Ah, vous voulez rendre à la volée - bon choix, mais inhabituel aux coûts modernes de RAM. Au lieu de cela, vous devez simplement rendre le caractère dans un tampon de trame au préalable, ou si votre appareil est extrêmement mince, dirigez directement (voir mon explication DMA ci-dessus) la ligne de caractères vers le DAC.
la source
Mis à part le pipelining (qui est vraiment ce que vous devez faire), il vous manque quelque chose de majeur ...
Les horloges du registre à décalage d'entrée parallèle et de sortie série pointent à 25 Mhz impairs, bien sûr, mais si vos personnages ont une largeur de 8 pixels, leur entrée est à seulement ~ 3,2 MHz, ce qui est facilement accessible pour la série LS de l'ère VGA, pour autant que cela vous devez avoir l'octet suivant prêt lorsque le registre à décalage se termine avec l'actuel (c'est là que le pipeline entre).
Générez une horloge de pixels à ~ 25 MHz et une horloge de mémoire à 1/8 de celle-ci pour piloter le tampon de texte et la ROM CG, puis canalisez cette mémoire et les trucs d'accès à la ROM CG.
Une autre astuce, la sortie du tampon de texte sera répétée pour chaque ligne dans une ligne de texte donnée, donc vous pourriez peut-être synchroniser les 80 octets de texte dans un tampon en anneau puis arrêter de lire le ram pour les 7 lignes suivantes (en supposant un 8 caractère de ligne), cela vous permet de libérer de la mémoire pour le CPU à utiliser, au prix d'avoir besoin de 80 octets de RAM accroché sur le côté de la chose.
la source
Alors, évidemment, cela ne fonctionne pas; vous avez besoin d'un pipeline.
1) Stockez les caractères de façon contiguë dans la mémoire. Commencez en haut à gauche.
2) Récupérez un caractère pendant l'intervalle de suppression. Continuez à récupérer les caractères dans l'ordre de la mémoire.
3) Pipeline chaque caractère décodé plus index de ligne dans la ROM.
4) Pipeline la sortie ROM dans un tampon.
5) Pipeline le tampon dans un registre à décalage. Lisez les pixels en continu à des intervalles de 40ns.
(Cela implique que vous devez charger un nouveau caractère dans le registre à décalage toutes les 320ns, ce qui pourrait même être faisable sans pipeliner le reste du système.)
6) Pendant la suppression horizontale, revenez au début de la ligne ou avancez au caractère suivant (c.-à-d. Début de la ligne suivante).
Bonus: comme vous n'avez besoin que d'un caractère toutes les 320ns, vous pouvez également lire une paire caractère + couleur et créer des caractères de couleur de style MSDOS ou de style spectre.
la source