¿Cómo es posible manejar pantallas VGA a frecuencias de reloj de píxeles tan altas?

12

Estoy trabajando en un circuito digital que utiliza componentes discretos para controlar una pantalla VGA de 640x480 en un modo de texto de 80x30.

Para una pantalla de 640x480, el reloj de píxeles es 25.175MHz, que tiene un período de alrededor de 40ns. No entiendo cómo se supone que puedo proporcionar un nuevo píxel a la pantalla con tanta frecuencia.

La arquitectura básica para mi circuito es la siguiente:

  1. El contador binario para píxeles horizontales cuenta de 25.175MHz a 800 (640 píxeles visibles + 160 para porche delantero, sincronización, porche trasero). A 800, incremente el contador de línea vertical (y restablezca a 525 líneas)

  2. Usando la posición horizontal y vertical, deriva la coordenada x, y del carácter actual.

  3. Usando la coordenada x, y del carácter, indexe en la memoria de video para recuperar el carácter ASCII.

  4. Utilice el carácter ASCII para indexar en la ROM de caracteres para obtener un patrón de bits para el carácter

  5. Utilice el registro de desplazamiento paralelo al serial para convertir una línea de caracteres de 8 píxeles a bits individuales a una frecuencia de reloj de píxeles

Si sigue la cadena, va: Contador -> RAM -> ROM -> Registro de desplazamiento paralelo a serie

Usando los componentes más rápidos que puedo encontrar, los retrasos de propagación y el tiempo de acceso suman alrededor de 15ns + 20ns + 70ns + 15ns = 120ns, mucho más que el período de 40ns para 25MHz.

A resoluciones y frecuencias de actualización aún más altas, puede tener relojes de píxeles muy por encima de 100MHz, que será un período de 10ns.

¿Cómo es posible proporcionar nuevos píxeles a la pantalla cada 10ns cuando solo el tiempo de acceso para RAM / ROM ya está muy por encima de él, sin siquiera considerar todas las otras señales en su sistema?

supershirobon
fuente
77
Utiliza una RAM de video dedicada y la registra directamente en su señal de video. Trabaja en averiguar qué mostrar mucho antes de que realmente lo muestre.
Hogar
2
Ve a leer sobre Maximite . Solo usa el hardware periférico de un MCU y algunas resistencias para manejar un puerto VGA. Comience examinando el periférico PIC32 que usa. Funciona bien. (Tengo un Maximite aquí.)
jonk
"The Cheap Video Cookbook" por "Don Lancaster"
Jasen

Respuestas:

17

Hay dos razones principales por las que encuentra este desafío.

Primero, está utilizando partes más antiguas y más discretas (integración de menor escala) de las que se habrían utilizado para hacer esto en la era de VGA.

Pero a continuación, los está utilizando de forma atípica. Específicamente, su enfoque no es lo pipelinedque significa que tiene que sumar múltiples retrasos al determinar su intervalo y, por lo tanto, calificar.

En contraste, los diseños digitales sincrónicos que intentan alcanzar la velocidad intentan hacer lo menos posible entre registros.

Si bien los detalles probablemente diferirían un poco, en términos generales funcionaría de la siguiente manera:

  • Incrementa o restablece la dirección, luego eso va en un registro.
  • Bloqueas la dirección en la memoria síncrona
  • Bloqueas la salida de la memoria síncrona
  • Se bloquea esto en la dirección del generador de caracteres síncrono
  • Bloquea la salida del generador de caracteres en el registro de salida
  • aplicar la búsqueda de paleta ...
  • en el DAC síncrono ...

Cuando desglosa una tarea como esta, solo obtiene un retraso combinatorio más un retraso de propagación y registra los tiempos de configuración y retención que necesitan ajustarse entre los relojes.

Un diseño construido de esta manera requerirá muchos relojes para producir una salida; la latencia será en realidad más alta que un diseño puramente combinatorio. Pero produce una nueva salida correcta en cada ciclo de un reloj mucho más rápido.

Y oye, es video, en realidad no importa si el CRT está dibujando una docena de píxeles detrás del contador de píxeles; por supuesto, lo tienes en cuenta en el momento de las señales de sincronización para que sean correctas en comparación con cuando los datos realmente sale del DAC.

En la práctica, casi todos los sistemas digitales complejos funcionan de esta manera, ya que es una gran idea, hasta que una CPU conectada llega a una dependencia de un resultado computacional anterior o una rama condicional ... Luego las cosas se ponen interesantes, ya que hablarían en la próxima clase de una clase de sistemas digitales, pero afortunadamente su situación VGA es mucho más simple, especialmente si todavía no se preocupa por los efectos de desgarro si el búfer de caracteres cambia mientras se dibuja la pantalla.

Como cuestión práctica si desea construir esto, hágalo en un FPGA. Eso forzará las memorias síncronas si usa las internas, o los registros de E / S sincrónicos si usa la memoria externa. Obtendrá muchos empujones hacia un diseño adecuado, la tela en sí será más rápida que sus partes discretas y, por supuesto, si comete un error, solo necesita girar los pulgares mientras se vuelve a compilar en lugar de pasar un largo día reconectando .

Chris Stratton
fuente
"especialmente si aún no te preocupas por los efectos de desgarro si el búfer de caracteres cambia mientras se dibuja la pantalla", es por eso que desde los primeros días de los coprocesadores de video, los coprocesadores tenían una manera de informar al proceso principal que no actualmente están volcando su memoria en la pantalla y si quieren cambiar el búfer de video, deberían hacerlo ahora.
John Dvorak
Creo que estás complicando demasiado esto. Él ya declaró que está usando un registro de desplazamiento de 8 bits que genera un bit por reloj de píxeles. Presumiblemente este es un registro de desplazamiento de 8 bits con pestillo. Eso significa que solo tiene que buscar un nuevo byte una vez cada 8 relojes de píxeles, por lo tanto, a una velocidad de 3.125MHz. Eso le da a todos los 320ns para llevar los datos al pestillo del registro de desplazamiento, que es mucho más largo que los 120ns que dijo que tomarían.
Chris_F
Para un caso monocromático de baja resolución muy simple, sí, el tiempo de bytes no sería demasiado desafiante, pero una parte clave de la pregunta era que el autor de la pregunta intentaba entender cómo funciona el rendimiento de los sistemas "reales" típicos de resolución no trivial. es posible. Y la respuesta es la misma que la de todos los demás sistemas digitales útiles: tecnología más rápida y diseño síncrono canalizado.
Chris Stratton
2

Usando los componentes más rápidos que puedo encontrar, los retrasos de propagación y el tiempo de acceso suman alrededor de 15ns + 20ns + 70ns + 15ns = 120ns, mucho más que el período de 40ns para 25MHz.

Olvida que un adaptador de gráficos nunca solo dibujaría un solo píxel, sino al menos una línea de exploración completa. Por lo tanto, este sería un problema completamente canalizable.

Además, no olvide que ha habido cinco décadas de hardware de producción de video hasta ahora. Su problema generalmente se resolvería con un tipo especial de RAM, en el que representa sus letras en un puerto, y que se lee secuencialmente en una señal de video DAC. Ese hardware es mucho más rápido de lo que estás viendo.

La arquitectura básica para mi circuito es la siguiente:

  1. El contador binario para píxeles horizontales cuenta de 25.175MHz a 800 (640 píxeles visibles + 160 para porche delantero, sincronización, porche trasero). A 800, incremente el contador de línea vertical (y restablezca a 525 líneas)

  2. Usando la posición horizontal y vertical, deriva la coordenada x, y del carácter actual.

No, ¿por qué harías eso? Simplemente colocaría su píxel de fila en un área contigua de memoria y lo colocaría linealmente en su DAC; si se trata de una implementación de CPU / MCU, ni siquiera dejaría que su CPU haga eso, sino una unidad DMA, programada para hacer nada más que tomar un valor tras otro y ponerlo, por ejemplo, en un puerto de datos paralelo, sin ninguna interacción con el núcleo de la CPU.

  1. Usando la coordenada x, y del carácter, indexe en la memoria de video para recuperar el carácter ASCII.

Ah, quiere renderizar sobre la marcha: buena elección, pero inusual a los costos modernos de RAM. En cambio, simplemente representaría el carácter en un búfer de fotograma de antemano, o si su dispositivo es extremadamente delgado, canalice directamente (vea mi explicación de DMA arriba) la fila de caracteres al DAC.

Marcus Müller
fuente
1
Si bien las cosas modernas tienden a preferir framebuffers pre-renderizados, obviamente son una mala opción si estás tratando de trabajar sin mucha memoria RAM. Si está haciendo esto en un FPGA, puede hacer que la máquina de estado DMA tome direcciones del mapa de celdas de caracteres y luego leer los glifos de caracteres correspondientes.
R .. GitHub DEJA DE AYUDAR AL HIELO
totalmente de acuerdo aquí! Por lo tanto, mi sección de respuestas sobre la tercera pregunta.
Marcus Müller
2

Aparte de la canalización (que es mucho lo que debe hacer), le falta algo importante ...

El registro de desplazamiento de entrada y salida en serie paralela marca los puntos a 25 Mhz impares, claro, pero si sus caracteres tienen, digamos, 8 píxeles de ancho, su entrada es de solo ~ 3.2MHz, que es fácilmente accesible para la serie LS de la era VGA, para todo eso debe tener listo el siguiente byte cuando el registro de desplazamiento finalice con el actual (aquí es donde entra la tubería).

Genere un reloj de píxeles a ~ 25MHz y un reloj de memoria a 1/8 de eso para controlar el búfer de texto y CG ROM, luego canalice esas cosas de acceso a la memoria y CG ROM.

Otro truco, la salida del búfer de texto se repetirá para cada línea dentro de cualquier línea de texto dada, por lo que tal vez pueda registrar los 80 bytes de texto en un búfer en anillo y luego dejar de leer el ram para las siguientes 7 líneas (suponiendo un 8 carácter de línea), esto le permite liberar la memoria para que la CPU la use, a costa de necesitar 80 bytes de memoria RAM colgada del costado.

Dan Mills
fuente
1

Obviamente eso no funciona; Necesitas una tubería.

1) Almacene los caracteres contiguamente en la memoria. Comience en la parte superior izquierda.

2) Obtener un personaje durante el intervalo de supresión. Continúe buscando caracteres en el orden de la memoria.

3) Canalice cada carácter decodificado más el índice de línea en la ROM.

4) Canalice la salida de ROM en un búfer.

5) Canalice el búfer en un registro de desplazamiento. Lea los píxeles continuamente a intervalos de 40 ns de esto.

(Eso implica que necesita cargar un nuevo personaje en el registro de desplazamiento cada 320 ns, lo que incluso podría hacerse sin canalizar todo el resto del sistema).

6) Durante la supresión horizontal, regrese al inicio de la línea o avance al siguiente carácter (es decir, al comienzo de la siguiente línea).

Función de bonificación: dado que solo necesita un personaje cada 320ns, también puede leer un par de caracteres + color y hacer caracteres de color estilo MSDOS o estilo Spectrum.

pjc50
fuente