El 7 de septiembre de 2026, nand2mario presentó zSST, una implementación en SystemVerilog de 3dfx Voodoo Graphics, también conocida como SST-1. El proyecto surgió tras un mes de trabajo en z486_MiSTer y del interés por las tarjetas 3D que llegaron después de la primera mitad de los años noventa. Need for Speed II SE fue la referencia inicial, con sus texturas, niebla y fluidez.

Glide triangle API
void grDrawTriangle(const GrVertex *a, const GrVertex *b, const GrVertex *c);

zSST está integrado con la CPU z486 y el resto del hardware del PC en z486 XL. El resultado es un PC DOS con gráficos Voodoo dentro de la lógica programable de una placa Xilinx KV260. Tomb Raider ejecuta su renderizador 3dfx original. zSST admite triángulos preparados, filtrado de texturas, mipmapping, pruebas de profundidad y alpha, niebla, blending, dithering, acceso al framebuffer y cambios de buffer. También acepta interfaces de preparación en punto fijo y punto flotante. Las pruebas de hardware se concentran actualmente en Tomb Raider. La compatibilidad más amplia y las generaciones posteriores de Voodoo quedan para una fase futura.

La CPU y el renderizador funcionan a 100 MHz en la KV260. La placa ofrece suficiente lógica, bloques DSP, memoria integrada y ancho de banda DDR para el diseño combinado. La DE10-Nano no tiene espacio suficiente para añadir los gráficos. La KV260 utiliza su DDR integrada y no necesita un módulo SDRAM externo.

La implementación toma como referencias el código fuente de Glide publicado por 3dfx en 1999 y la especificación SST-1. 3dfx publicó Glide antes de que NVIDIA adquiriera sus activos gráficos principales en diciembre de 2000. El código Glide conservado, la especificación SST-1, 86Box, los primeros trabajos de MAME sobre Voodoo y las trazas de SpinalVoodoo aportaron referencias de comportamiento y datos de prueba. La especificación define el comportamiento de los registros y los resultados, pero no describe el circuito original.

El acelerador tiene cinco registros de comandos principales. triangleCMD inicia un triángulo preparado, ftriangleCMD usa la interfaz de preparación en punto flotante, nopCMD vacía la pipeline y puede restablecer los contadores de estadísticas, fastfillCMD limpia un rectángulo limitado de color o profundidad y swapbufferCMD cambia el buffer mostrado de inmediato o durante el retorno vertical. Otros registros contienen coordenadas, gradientes y estado de renderizado. Las regiones mapeadas en memoria gestionan las cargas de texturas y el acceso directo al framebuffer.

La llamada de Glide grDrawTriangle recibe tres vértices después de que la CPU anfitriona haya transformado la geometría, calculado la iluminación, recortado el resultado y proyectado la escena sobre la pantalla. La SST-1 no incorpora hardware de transformación e iluminación. El rasterizador identifica los píxeles del triángulo e interpola color, profundidad y coordenadas de textura. La unidad de texturas lee y filtra texels. La ruta del framebuffer realiza las pruebas de visibilidad, aplica niebla y blending, y escribe el resultado.

La Voodoo original reparte el trabajo entre el Frame Buffer Interface, o FBI, y la Texture Mapping Unit, o TMU. A 50 MHz, su cifra máxima anunciada es de un píxel de salida texturizado y con prueba de profundidad por ciclo, es decir, 50 millones de píxeles por segundo. Varios píxeles avanzan simultáneamente por etapas distintas. Cada píxel necesita varias etapas para completarse. Una pipeline llena puede aceptar un píxel por ciclo cuando la memoria mantiene el ritmo. Esta arquitectura ayudó a ofrecer juegos 3D con texturas a 30 FPS o más.

El software puede enviar valores en punto flotante, pero la mayor parte del renderizado utiliza aritmética de punto fijo. Los formatos internos son 12.4 para X e Y de pantalla, 12.12 para rojo, verde, azul y alpha, 20.12 para la profundidad Z, 14.18 para S/W y T/W de textura, y 2.30 para el recíproco de W. Los registros fvertex, fstart y los gradientes de punto flotante aceptan valores IEEE de precisión simple. SST-1 los convierte a estos formatos fijos. Después, la interpolación se basa principalmente en sumar incrementos precalculados.

Para corregir la perspectiva, la TMU interpola S/W, T/W y 1/W y divide los dos primeros valores por el tercero. Selecciona un nivel de mipmap y aplica filtrado bilineal a cuatro texels vecinos. zSST utiliza cuatro etapas iniciales para calcular la perspectiva y el nivel de detalle. La generación de direcciones, la búsqueda en caché, la decodificación de formatos y la combinación de texturas admiten texturas basadas en paletas y texturas codificadas con NCC.

La ruta de píxeles del FBI tiene seis etapas registradas. F0 selecciona las fuentes, comprueba la chroma key y prepara los valores Z/W. F1 aplica las funciones de combinación de color y alpha. F2a ejecuta las pruebas de alpha y profundidad y consulta el factor de niebla. F2b aplica la niebla. F3 reconstruye el color de destino y realiza el alpha blending. F4 convierte a la precisión del framebuffer, aplica dithering y utiliza las máscaras de escritura. La división de etapas cumple el objetivo de frecuencia del FPGA y conserva un píxel por ciclo.

El acceso a memoria fue el principal reto de implementación. La Voodoo original proporciona al FBI y a la TMU rutas de memoria separadas de 64 bits. El intercalado de texturas entre cuatro bancos usa la paridad par o impar de la columna y la fila. Así, cada ventana de 2x2 texels llega a los cuatro bancos en paralelo. El FBI aplica una disposición parecida a los datos de color y profundidad o alpha. Su máximo es de un píxel renderizado por ciclo y dos píxeles por ciclo durante las limpiezas. A 50 MHz, cada ruta de 64 bits ofrece teóricamente 400 MB/s, 800 MB/s en total. Las dos rutas mantienen funciones separadas.

La KV260 accede a la DDR compartida mediante puertos AXI. Linux, el PC FPGA y la salida de vídeo compiten por esa memoria. Un puerto de 128 bits a 100 MHz ofrece teóricamente 1,6 GB/s. Con una solicitud pendiente, las mediciones alcanzan 1.370 MiB/s para una lectura de 4 KiB y 189 MiB/s para una lectura de 64 bytes. Los primeros datos suelen llegar después de unos 280 ns, aproximadamente 28 ciclos a 100 MHz. Algunas esperas son más largas.

zSST utiliza una caché de texturas de 8 KiB con líneas de 64 bytes. Puede mantener ocho cargas de líneas pendientes. Una cola de replay conserva las muestras cuyos datos aún faltan. Un reorder buffer de 64 entradas entrega los resultados en su orden original. La ruta del framebuffer tiene cachés separadas de 4 KiB para color y profundidad o alpha. Los write combiners agrupan actualizaciones contiguas de 16 bits en solicitudes de 128 bits. El forwarding mantiene las dependencias cuando una operación posterior de profundidad o blending necesita un valor modificado por un píxel anterior. FBI y TMU comparten el puerto AXI HP2 del renderizador. El PC utiliza HP0 y la salida de vídeo usa HP3.

Las pruebas de simulación modelan el timing de DDR, la TMU, el FBI, la arbitraje compartida y la interfaz frontal. Las lecturas llegan después de al menos 26 ciclos, las escrituras tienen un límite de ritmo y las pruebas del renderizador completo permiten 32 lecturas pendientes. A 100 MHz, zSST alcanza 78,5 MPix/s con triángulos texturizados y 72,8 MPix/s con pruebas de profundidad y blending. Las estimaciones publicadas para Voodoo 1 a 50 MHz son de 43 y 37 MPix/s con grupos de funciones comparables. Las cargas de trabajo son diferentes, por lo que los resultados muestran un rango aproximado y no una mejora de velocidad medida.

En la placa, el nivel 2 de Tomb Raider produjo 237 cambios de buffer mostrado en unos 20 segundos, aproximadamente 12 por segundo. La medición cuenta cambios de buffer y no usa un contador de FPS del motor. Los primeros resultados señalan a la CPU como principal límite. La competencia por la DDR también puede influir. El z486 XL a 100 MHz alcanza 38,5 FPS en Doom con el máximo nivel de detalle y 8,1 FPS en Quake 1.06. Esas cifras son aproximadamente un 20 % superiores a las del sistema DE10-Nano a 85 MHz. La mejora ronda el 23 % en Doom y el 19 % en Quake. Una caché L2 write-back de 512 KiB en UltraRAM ayuda a la CPU a aprovechar la DDR.

En el diseño integrado XCK26, zSST utiliza aproximadamente 29.500 LUT, 28.100 flip-flops, 14 bloques RAMB36, 8 bloques RAMB18 y 97 bloques DSP. El diseño combinado de PC y gráficos cumple el timing a 100 MHz. zSST y z486 XL son proyectos de código abierto. La versión z486_XL_20260906 de z486 XL incluye el soporte Linux y la aplicación necesarios para iniciar imágenes de disco DOS en una KV260. El proyecto reconoce a SpinalVoodoo por sus trazas Glide y capturas de referencia, a 86Box por sus referencias de implementación y a Fabien Sanglard por su análisis de la memoria de Voodoo 1.