Anotación
Locura Todas las edades Sumiso
Al diseñar cualquier módulo en FPGA, a veces viene a la mente la idea de un uso no bastante estándar del entorno de diseño en sí y las herramientas que proporciona para el diseño. En este breve artículo, veremos cómo, con la ayuda de la herramienta de gestión ambiental implementada en Tcl, podemos literalmente dibujar fotografías, pinturas, retratos y memesics en el FPGA.
Una "ruta de diseño" tan inusual se implementó hace un año y medio, pero solo ahora surgió la idea de organizarla en forma de una nota, en la que hay poca práctica en el uso de scripts Tcl para administrar el entorno de diseño, en este caso Vivado. Sin embargo, con modificaciones menores, todo se puede adaptar fácilmente a otros entornos de desarrollo, por ejemplo, Quartus II.

Introduccion
Por supuesto, la idea no vino a la mente de la nada. Su aparición fue promovida por mi empleo en proyectos de procesamiento de imágenes y gestión de secuencias de video en FPGA. A todos les sucede que cuando se sientan ante una solución a un problema, cada herejía viene a la mente por qué no funciona o funciona exactamente como debería, pero no como esperamos.
Al resolver el problema, tuve que recurrir a una de las herramientas del entorno de Vivado, a saber, colorear los componentes y módulos correspondientes en el proyecto después de la colocación, el rastreo y el análisis en gráficos de tiempo infinitos.
Como resultado, pinté varios bloques lógicos configurables de CLB en varios colores, y me di cuenta: estos son los píxeles de la imagen, así que puedo tratar de dibujar qué hilo es la imagen, haciendo coincidir cada píxel con su propio CLB de color ... bueno, comenzó
¿Cómo nos ayudará Tcl?
Supongamos que tenemos una pequeña imagen de tamaño 100x100 píxeles. Ahora suponga que para colorear el CLB, necesitamos hacer dos cosas: seleccionar el CLB y seleccionar el color. En la imagen de 100x100 tenemos 10,000 píxeles y hacer ese color manualmente es bastante tedioso, especialmente porque las acciones son las mismas y repetitivas. Por lo tanto, pintar manualmente cada CLB no es una opción y debe usar Tcl y scripts. ¿Pero por dónde empezar?
Lo primero que se me ocurrió fue encontrar el equipo adecuado responsable de asignar el color al elemento seleccionado. Afortunadamente, al realizar acciones manualmente, Vivado muestra los comandos Tcl apropiados en la consola, y parece que el problema de búsqueda debe resolverse lo más rápido posible. Sin embargo, no estaba allí. Vivado simplemente ignora la salida del comando para resaltar los elementos seleccionados, y la única opción para encontrar el comando, y estaba absolutamente seguro de que debería ser, es sumergirse de lleno en la guía Tcl disponible en Vivado, que tiene casi 2000 páginas [1].
No se desespere, la palabra clave "resaltar" encontró rápidamente el comando correspondiente, que se llama resaltar_objetos. Este comando resalta los objetos especificados o seleccionados en un color específico, especificado usando opciones. Las opciones para el comando highlight_objects son las siguientes:
- color_index - (opcional) el valor válido del argumento de la opción debe ser un número del 1 al 20. El color en el que se pintará el objeto seleccionado está determinado por su número de serie de la paleta de colores predefinida, que se puede encontrar en Colores → Resaltar en la sección de menú Herramientas → Configuración .
- rgb - (opcional) establece el color del objeto seleccionado en formato RGB
- color : (opcional) resalta el objeto seleccionado en uno de los siguientes colores: rojo, verde, azul, magenta, amarillo, cian y naranja
Las opciones restantes del comando se relacionan con la configuración del sistema del comando en sí y no nos serán útiles. Sin embargo, cuando use el comando highlight_objects, tenga en cuenta que dos o más opciones de coloración no se pueden aplicar al mismo tiempo.
Obviamente, una opción que establece un color arbitrario en formato RGB es adecuada para nuestra tarea: la opción rgb
Ahora no sería malo obtener los valores de píxeles de la imagen, pero no pude encontrar la imagen que se presentaría en formato de mapa de bits. Al abrir cada archivo con un editor de texto, no fue posible encontrar líneas con un valor de píxel. Por supuesto, no escribí un programa para convertir imágenes a formato de mapa de bits, sino que simplemente subí a Internet para buscar una solución preparada. No fue demasiado largo para buscar. Al final resultó que, la tarea de convertir una imagen a un formato de mapa de bits (es decir, cuando vemos los valores de píxeles de una imagen sin comprimir) es bastante relevante (probablemente, dicha tarea se asigna a los estudiantes programadores como tarea para el trabajo de laboratorio). Una búsqueda corta resultó en github, desde donde se descargó el programa Image2Bitmap [2].
El programa requiere una entrada de imagen y genera los valores de píxel en forma de matriz C con valores de píxel hexadecimales en formato RGB565. Este formato dice que la codificación de color para el componente rojo usa 5 bits, verde 6 bits y azul 5 bits. Esto resultó ser suficiente para el trabajo. Ahora todo lo que se requiere es asignar los valores obtenidos directamente a las secciones pintadas (corte).
Selección de FPGA
Cuanto más grande es el FPGA, más recursos lógicos contiene, lo que significa que el "campo para la creatividad" en sí mismo es más grande y la imagen será más clara. Cabe señalar de inmediato que "decorar" es un proceso bastante largo y puede tomar una cantidad de tiempo decente, dependiendo del tamaño de la imagen. Para las pruebas, vale la pena elegir un FPGA con una pequeña cantidad de recursos. Por ejemplo, la familia Spartan-7. Después de la prueba, puede cambiar el FPGA a más "gordo", por ejemplo, de la familia Ultrascale +.
Iniciamos Vivado y creamos el proyecto.
Seleccionamos el cristal xc7s6cpga196-2, en el que dibujaremos la imagen de prueba

Para mostrar el dibujo, necesitamos abrir la imagen del cristal en sí, sin embargo, esto se puede hacer después de la etapa de síntesis o elaborar. En Vivado, para esto necesitamos crear un módulo ficticio en cualquier idioma.

Agregue un script al proyecto Tcl.
a. Para hacer esto, cree un archivo con la extensión ".tcl" en la carpeta con el proyecto, por ejemplo, "fpga_painter.tcl"

b. Vaya a Vivado y agregue este archivo al proyecto.

c. Después de actualizar la jerarquía del proyecto, deje el archivo inactivo.

Después de crear el módulo, aparecerá en la ventana de la jerarquía del proyecto y el botón Abrir diseño elaborado estará disponible para nosotros. Empújalo.

Después de abrir Diseño elaborado, vaya a Ventana → Dispositivo. Aparecerá una pantalla del campo de nuestro FPGA.

La preparación ha terminado, comenzamos a escribir un guión.
Definición de parámetros y procedimientos.
Imagen de prueba
Primero, depuremos el algoritmo / código como tal en una imagen pequeña, digamos 5x3, y luego ejecútelo "al máximo".
Abra Paint, limite el campo de imagen a 5x3 píxeles (puede tomar cualquier color). Guarde el archivo como "5x3.png"

Abra el programa Image2Bitmap y convierta nuestra imagen en una matriz RGB565.

Después de la conversión, el programa nos dará una matriz de 15 píxeles.
*uint16_t image = { 0xf800, 0x07e0, 0x001f, 0x8410, 0x8010, 0xfbe4, 0xff80, 0x2589, 0x051d, 0x3a59, 0xa254, 0xbbca, 0xfd79, 0xef36, 0x9edd, };*
Preparación de datos
Antes de continuar con el procesamiento de píxeles, transformamos los datos generados por Image2Bitmap en una lista simple en la que se escriben los valores de píxeles hexadecimales. Copiaremos los datos del programa y los guardaremos en el archivo pic_array.dat, que debe ubicarse en la carpeta del proyecto.

Al iniciar el script creado, tenemos que procesar el archivo "pic_array.dat". Vale la pena señalar que el número de elementos en la línea devuelta por Image2Bitmap no coincide con el número de píxeles en la línea de la imagen convertida, por esta razón crearemos una lista separada de "píxeles".

Al leer un archivo, debe ignorar la primera línea "uint16_t image = {" y la última "};". Para omitir la primera línea al leer un archivo, simplemente coloque la línea de lectura antes del ciclo de lectura del archivo completo.

Después de leer el archivo completo, veremos que la última línea del archivo "};" se ha convertido en un elemento de la lista, que simplemente se elimina.

Esto completa la formación de la lista con valores de píxeles hexadecimales. Ahora comencemos a procesarlos.
Tamaño de imagen
Una vez más, eche un vistazo al campo FPGA y la imagen. El campo FPGA se divide en secciones (SLICE), que tienen las coordenadas horizontales correspondientes "X" y vertical "Y". Por ejemplo, SLICE_X6Y36.

La imagen, a su vez, tiene píxeles, también con coordenadas horizontales y verticales. Al superponer la imagen en el FPGA, debemos combinar el píxel superior izquierdo con la sección superior izquierda del FPGA. En este caso, el cristal seleccionado tiene una sección superior con la coordenada X0Y49.

El tamaño de la imagen estará determinado por el número de secciones en el FPGA horizontal y verticalmente. Para el cristal seleccionado, la coordenada horizontal de las secciones varía de X0 a X131, y la coordenada vertical de Y49 a Y0. Se deduce que, en teoría, podemos dibujar una imagen de tamaño 132x50 en el cristal seleccionado.
Parámetros iniciales
Para resumir: los parámetros iniciales de nuestro script serán:
X posición inicial de la sección: nombre de variable start_x

Posición de inicio de sección en el eje y: nombre de variable start_y

Ancho de imagen (para la imagen de prueba es 5): variable w

Altura de la imagen (para la imagen de prueba es 3): variable h

Ajuste de color de píxel
Image2Bitmap proporciona una matriz de píxeles en formato RGB565 como un número de 16 bits escrito en formato hexadecimal. Deberíamos:
Convierte el valor de píxel a formato binario. Esto se puede hacer usando el procedimiento hex2bin, que se puede encontrar en [3]

Haga coincidir los bits con los componentes de color correspondientes:
• El componente rojo de R [15:11]

• Componente verde G [10: 5]

• Componente azul B [4: 0]

Explicación: el orden cambia debido al hecho de que el procedimiento hex2bin devuelve una cadena en la que la numeración de los elementos comienza con 0, es decir, el 15º bit corresponde al 0º elemento de la cadena y el 0º bit corresponde al 15º elemento de la cadena
Convierta el valor del componente de color de binario a decimal. Esto se puede hacer usando el procedimiento bin2dec, que se puede encontrar [3]:


Convierta valores de píxeles de RGB565 a formato RGB888, para una visualización de imagen más fluida. Esto se hace usando dos listas, que se pueden encontrar en [4]. Cómo funciona
• La resolución de los componentes de color R y B es de 5 bits. Tomando el valor decimal del componente, lo comparamos con la posición del número escrito en la lista t5, y el valor del componente cambia al valor en la tabla



• De manera similar para el componente G y la tabla t6


Disponibilidad de sección
Dentro de algunos FPGA hay recursos especiales o vacíos que pueden interrumpir la numeración secuencial de las coordenadas de sección. Por ejemplo, en la figura siguiente puede ver que la numeración de la sección está interrumpida (cristal xc7s50)

Por esta razón, antes de teñir, primero verificamos la existencia de la sección. Si existe, luego pinta, si no existe, pasa al siguiente píxel

Sección de tinción
Color de sección definido, sección marcada. Ahora el color debe asignarse a las secciones con el comando highlight_objects:

Vector → Matriz bidimensional
Al principio, convertimos los datos de la imagen en una lista de píxeles, que almacena un escaneo progresivo de la imagen. Para organizar la imagen, presentamos dos variables, x e y, que corresponderán a la posición de los píxeles en la imagen. Al leer secuencialmente los elementos de la lista de píxeles, formaremos una imagen utilizando dos bucles for: uno por el número de líneas, el segundo por la posición del píxel en la línea


Listado completo de guiones
Listado de fpga_painter.tcl #https://tcl.tk/ #http://www.tune-it.ru/web/il/home/-/blogs/-rgb888-<->-rgb565----- #https://github.com/FoxExe/Image2Bitmap/releases/tag/0.5 # set start_x 0; # set start_y 49; # set w 5; # ( ) set h 3; # ( ) proc hex2bin hex { set t [list 0 0000 1 0001 2 0010 3 0011 4 0100 \ 5 0101 6 0110 7 0111 8 1000 9 1001 \ a 1010 b 1011 c 1100 d 1101 e 1110 f 1111 \ A 1010 B 1011 C 1100 D 1101 E 1110 F 1111] regsub {^0[xX]} $hex {} hex return [string map -nocase $t $hex] } proc bin2dec bin { #returns integer equivalent of $bin set res 0 if {$bin == 0} { return 0 } elseif {[string match -* $bin]} { set sign - set bin [string range $bin[set bin {}] 1 end] } else { set sign {} } foreach i [split $bin {}] { set res [expr {$res*2+$i}] } return $sign$res } ############### #RGB565 -> RGB888 using tables set t5 [list 0 8 16 25 33 41 49 58 66 74 82 90 99 107 115 123 132\ 140 148 156 165 173 181 189 197 206 214 222 230 239 247 255] set t6 [list 0 4 8 12 16 20 24 28 32 36 40 45 49 53 57 61 65 69\ 73 77 81 85 89 93 97 101 105 109 113 117 121 125 130 134 138\ 142 146 150 154 158 162 166 170 174 178 182 186 190 194 198\ 202 206 210 215 219 223 227 231 235 239 243 247 251 255] ############### # . set script_path [get_property DIRECTORY [get_projects *]] cd $script_path # set fId [open {pic_array.dat} r] # , set pixels [list ] # . gets $fId line # . . while {[gets $fId line] > 0} { set pixels [concat $pixels $line] } # pixels "};", Image2Bitmap set pixels [lrange $pixels 0 end-1] # pixels set pix_num 0; # for {set y 0} { $y < $h } {incr y} { # ( ) set Y [expr {$start_y - $y}] # for {set x 0} { $x < $w } {incr x } { set pix_val [lindex $pixels $pix_num]; incr pix_num # binary set pix_bin [hex2bin $pix_val] ; # set R_bin [string range $pix_bin 0 4] # set R_dec [ bin2dec $R_bin ] # t5 set R [lindex $t5 $R_dec] # set G_bin [string range $pix_bin 5 10] set G [lindex $t6 [ bin2dec $G_bin ]] set B_bin [string range $pix_bin 11 15] set B [lindex $t5 [ bin2dec $B_bin ] ] # set X [expr {$start_x + $x}] #, set cond [get_sites "SLICE_X${X}Y${Y}"] if {$cond ne ""} { # highlight_objects [get_sites "SLICE_X${X}Y${Y}"] -rgb "$R $G $B" } puts "X = $XY = $Y; $R $G $B" } } close $fId puts "Complete::Check FPGA field::Window->Device"
Prueba
Para comenzar a probar, asegúrese de que el campo FPGA esté disponible para usted, es decir Una de las etapas de diseño es abierta: elaborada, síntesis o implementada. Para mostrar el campo FPGA, seleccione Ventana → Dispositivo

Abra el archivo pic_array.dat y copie los datos de Image2Bitmap en el archivo. Guardar archivo

Abramos el guión. Establezca la coordenada de los píxeles superiores izquierdo 0 y 49, el tamaño de la imagen de prueba es de 5 por 3 y ejecute el script. Para hacer esto, haga clic derecho en el campo de secuencia de comandos y seleccione Ejecutar.

Vaya a la consola Tcl y asegúrese de que el script se haya ejecutado.

Vaya a la pestaña Dispositivo y asegúrese de que las celdas estén coloreadas en el color apropiado.

Ahora podemos tomar cualquier imagen, convertirla al tamaño deseado y completar el campo FPGA. A continuación hay algunos ejemplos.
PD: la asignación de color personalizada reemplaza la configuración de color predeterminada de Vivado

Referencias
- UG835. Guía de referencia de TclCommand de Vivado Design Suite
- https://github.com/FoxExe/Image2Bitmap/releases/tag/0.5
- https://tcl.tk
- http://www.tune-it.ru/web/il/home/-/blogs/conversion-rgb888 - <-> -rgb565-and-protection-mushrooms-from-fading