2019/12/22

VGA Rendering de simulación FPGA

Mientras estudiaba "Designing Video Game Hardware in Verilog" me hallé con que tenía que diagnosticar por que no funcionaban bien mis adaptaciones del código provisto a la Nexys 4 DDR que tengo con los ejemplos correspondientes a VGA (o mi doble adaptación a VGA por ser CRT).

Para no tener que pasar por todo el prolongado ciclo de modificar, sintetizar, implementar, generar el bitstream, burn it y tener que sacar el trasero de la silla para decirle al monitor que tome la entrada VGA en lugar del HDMI me hice un programita en TCL/TK que toma la salida de la simulación y me hace el render de las señales.

La verdad es que por lo valioso en términos educativos de este proyecto ni me molesté en ver si alguien ya lo había hecho, quizás por fin haya logrado aportar algo realmente útil. Mientras escribo esto veo que Xilinx tiene un repo de scripts para Vivado pero no llego a ver rápido si hay manera de ganarse una ventana dentro de la IDE, así que quedará para la Caja del Futuro.


En términos más formales:

El objetivo es hacer el render de una señal VGA generada probablemente por una simulación de un diseño Verilog o VHDL.

Los historias de usuario vienen a ser, "como usuario quiero que..."
  • Haga render de un frame
  • Haga render de varios frames consecutivos
  • Haga render de un frame  en "tiempo real", o sea, a medida que el simulador emita los datos
  • Haga render de varios frames consecutivos en "tiempo real"
  • Ajuste automático de resolución (640 x 480 la actual) 
  • Que entienda archivos standard tipo VCD
  • Que se pueda avanzar y retroceder
  • Que se pueda avanzar y retroceder usando el dispositivo ShuttleProV2


En verde lo que hice, no creo que avance con el resto pues esto es sólo un medio para lo que realmente quiero y no quiero que me distraiga.


Dado que hace muchos años trabajé con TCL/TK y me gustó y además Vivado usa TCL, más vale que empiece a recuperarlo, decidí usarlo para esta actividad.


En la carpeta "evolucion" dejé registrada la... evolución de mi acercamiento al problema, desde generar un patrón programáticamente en TCL/TK, pasando por mostrar las hsyncs y vsyncs, leer de un archivo, de STDIN y que finalmente funcione.

Los ejemplos 01_* a 04_* son los de "calibración", los restantes ya toman la salida de la simulación.





Entre las versiones 05_patternFromFile.tcl y 06_single_frame.tcl las diferencias significativas son:



  • Abstracción: en lugar de string index por todos lados, procs.
  • Lectura por STDIN
  • update para ver el rendering en tiempo real
  • y está bien alineado

La diferencia con la versión final, render.tcl es el multiframe


Con respecto a la salida de la simulación, primero investigué y no hay manera sencilla de acceder a lo generado pues está en una base de datos de formato desconocido para mi, así que opté por usar $strobe en el testbench con algo parecido a esto:



always @(negedge clock)
   $strobe("%b %b %b #%h%h%h", clock, hsync, sync, R, G, B);


Hay que generar el color tal que lo entienda TK o hacer una función adaptadora, opté por lo primero, mirá el código.


Podría quitar el clock ya que siempre es cero.

La simulación debe correr durante unos 8 ms para tener un frame completo entre vsyncs.




Me gustaría agregar colores distintos para las zonas no visibles que ahora está en negro y se confunde con la barra negra de la derecha, pero por ahora esto me sirve.


Es bastante lento, no me puse a optimizar, ni sé si se puede, de mis motivos originales sólo cumplo con no levantarme de la silla para cambiar la entrada del monitor.

Hay otra ventaja, la posibilidad de ver un sólo frame de una secuencia, que dependiendo del circuito real quizás no se pueda en la FPGA sin agregar lógica.




El video está fuertemente editado para que sólo se vea lo esencial de la interacción y el primer frame que no se muestra por no tener VSync está omitido, luego es tiempo real en una AMD A10-7700K Radeon R7.

Tambien corresponde a la versión de un solo frame, sin la simpática rayita blanca que muestra donde está dibujando, indispensable para multi frame.

El código en github

Esta es la captura de la última versión, con la simpática rayita y los límites de lo visible enmarcados en verde:




No hay comentarios:

Publicar un comentario