Diseño e implementación de un Sniffer USB utilizando un FPGA Spartan-3. El cual permite capturar todos los bits de información que se transmiten a través del bus, filtrarlos y enviarlos a un ordenador para ser analizados, permitiendo incluso la detección de errores en la trama.
La implementación fue realizada sobre una FPGA Xilinx XC3S200-FT256 utilizando como lenguaje de descripción en VHDL.
1. SNIFFER USB 2.0 (FULL SPEED)
Julián S. Bruno, Jerónimo F. Atencio, Pablo H. Gómez Martino
Departamento de Ingeniería Electrónica
Universidad Tecnológica Nacional – FRBA
Av. Medrano 951, Buenos Aires, Argentina
email: jbruno@electron.frba.utn.edu.ar, jfa47@yahoo.com.ar, pgomezm@gmail.com
RESUMEN
El presente trabajo describe el diseño e implementación de
un sniffer USB desarrollado sobre FPGA. El cual permite
capturar toda la información que es transmitida a través del
bus, filtrarla y enviarla a un ordenador para ser analizada,
permitiendo incluso la detección de errores en la trama.
Detecta los distintos estadios del bus diferencial sin
interferir con él. Este tipo de sniffer presenta varias
ventajas frente a sus más tradicionales competidores, los
sniffers USB de software, que no son más que una pieza de
software que captura los paquetes a nivel del driver del
Host USB, perdiendo totalmente de vista otros problemas
que podrían aparecer en la capa de hardware del bus. Por
otro lado, no siempre es posible disponer de un sniffer de
software en el sistema donde se encuentra el Host
controller. La implementación fue realizada en VHDL
sobre una FPGA Xilinx XC3S200-FT256.
1. INTRODUCCION
En una transmisión de datos por USB pueden intervenir
tres tipos de dispositivos: el Host controller, los Devices y
los Hubs conectados físicamente en una topología tipo
estrella. En un sistema USB solo existe un Host controller,
el cual tiene integrado un Root Hub que le provee más
puntos de conexión.
Un Device puede estar formado por una o más
Interfaces, que se comunican independientemente con las
aplicaciones en el ordenador. Estas, a nivel de hardware,
pueden contener varios Endpoints. Una Function se
presenta al sistema como una colección de Interfaces. La
comunicación entre los extremos se realiza entre los
buffers del lado Host controller y los Endponits del lado
Device, denominándose a este canal de comunicación Pipe.
A nivel lógico, USB se comporta como un bus
bidireccional, transportando datos de un Device
determinado hacia el Host controller y viceversa. La
especificación USB 2.0 [1] establece tres velocidades de
tasa de transferencia con sus respectivas denominaciones:
480 Mb/s (High speed), 12 Mb/s (Full speed) y 1,5 Mb/s
(Low speed). El sistema USB transmite la información a
nivel físico usando un par diferencial (D+ y D-), en el cual
se encuentra embebido el reloj del sistema. Para realizar
esto, se utiliza el código de no retorno a cero invertido
(NRZI) y la inserción de un bit (bit stuffing) para
garantizar una adecuada transición del bus.
La especificación USB 2.0 define los tipos de
transferencia de información con sus características
particulares, ver Tabla 1. Cada transferencia de datos se
divide en una o varias transacciones, las cuales están
formadas por paquetes de datos [2]. A su vez, el bus USB
trabaja con multiplexación por división de tiempo (TDM),
definiendo de esta manera una trama temporal (frame) en
la cual serán enviadas las distintas transacciones. Estas
ocupan una porción de tiempo determinada, dependiendo
del tipo de transferencia a la cual pertenecen. Los
conceptos de transferencia, transacciones, paquetes y
tramas se pueden observar en la Fig. 1.
El Host controller es el encargado de velar para que
todas las transacciones se lleven a cabo en el menor tiempo
posible y es el responsable de particionar el tiempo del bus
en tramas. Estas comienzan con un paquete de inicio de
trama (SOF) y terminan con una señalización en el bus que
indica el fin de trama (EOF). El Host Controller trabajando
con dispositivos Full speed, genera paquetes SOF en
intervalos de un milisegundo periódicamente.
Dentro de cada trama, se transmiten una o varias
transacciones, que a su vez están formadas por paquetes de
cuatro tipos diferentes: Token, Data, Handshake y Special.
Todos estos paquetes comienzan con un campo de
sincronismo (SYNC), de 8 bits de longitud, usado para
sincronizar el reloj local del Device con el reloj del Host
controller, seguido de un campo identificador del paquete
(PID) de la misma longitud. A continuación y dependiendo
del PID, podrán venir distintos. Todos los paquetes
terminan con una señalización de fin (EOP), cuya longitud
es de 3 tiempos de bits. Estos cuatro tipos de paquetes
tienen diferentes subtipos, como se puede observar en la
Tabla 2, según lo estipula la norma USB 2.0 (Full speed).
Para controlar errores en la información, cada paquete
incluye un campo que contiene un código de redundancia
cíclica (CRC) [3]. El protocolo usa dos polinomios
distintos para el cálculo del CRC: CRC5 y CRC16 (según
sea un paquete de control o de datos respectivamente).
2. Tabla 1. Clasificación de transferencias
Transferencia Característica Uso típico
Control No periódica, ráfagas. Configuración
Isócronas Periódicas. Webcam, Teléfono
Interrupt Pocos datos, baja frecuencia. Mouse, Teclado
Bulk
No periódicas, muchos datos,
usan el ancho de banda
excedente.
Impresora, Scanner y
Disco Rígido
Pipe
Transferencia 0
Transacción 0-0 Transacción 0-1 Transacción 0-2
Pipe
Transferencia 1
Transacción 1-0 Transacción 1-1 Transacción 1-2
Trama 0
SOF EOF
Token, Data,
Handshake (0-0)
Token, Data,
Handshake (1-0)
1 ms
Trama 1
SOF EOF
Token, Data,
Handshake (0-1)
Token, Data,
Handshake (1-2)
1 ms
Fig. 1. Esquema de una transferencia.
El paquete TOKEN encabeza todas las transacciones de
información entre el Host controller y el Device. Hay
cuatro subtipos: IN, OUT, SOF y SETUP.
En la Fig. 2 se aprecia el paquete SOF, él cual contiene
el campo Frame number que se ve incrementando en cada
trama y finaliza con el campo CRC5. Este paquete es
enviado únicamente por el Host controller indicando el
inicio de la trama.
Los paquetes tipo IN y OUT son utilizados para
indicarle al Endpoint de un determinado Device, que a
continuación recibirá un paquete de datos o que deberá
transmitir uno. El Device es indicado con el campo Addr y
el Endpoint con el campo Endp. El paquete SETUP es
utilizado para el inicio de las transferencias de control. El
campo CRC5 es el control de error de los dos campos antes
mencionados. El formato de estos tres tipos de paquetes se
puede observar en la Fig. 3.
El paquete DATA, que se aprecia en la Fig. 4, es
transmitido a continuación de un paquete IN, OUT o
SETUP desde o hacia un Device. Los paquetes de datos
pueden tener un tamaño máximo de 1024 bytes, según lo
estipula la especificación USB 2.0 para dispositivos Full
speed. Si se deben transmitir más datos de información, se
tendrán que realizar varias transacciones. A estos datos se
les calcula el código de redundancia cíclica, el cual es
enviado en el campo CRC16.
Los paquetes de HANDSHAKE, indican el estado de
una transacción de datos y su formato es el indicado en la
Fig. 5.
Tabla 2. Tipos de paquetes
PID Type PID Name Descripción
Token
OUT Transacción desde Host a la Function
IN Transacción desde Function al Host
SOF
Indica el comienzo de la trama y el
número de trama.
SETUP
Transacción de control, para el
Endpoint cero.
Data
DATA0 Paquete de datos par.
DATA1 Paquete de datos impar.
Handshake
ACK El paquete recibido no tiene errores.
NAK
El receptor no puede recibir el dato, o
no tiene dato para transmitir.
STALL
El Endpoint esta detinido o esa
transferencia de control no esta
soportada.
Special PRE
Habilita las transferencias low-speed
desde el Host controller hacia el Device
2. EL SNIFFER
El sniffer está compuesto por dos partes: hardware y
software. En este trabajo se desarrolla la implementación
del sniffer en hardware. El software es el encargado de
seleccionar qué paquetes de datos se desean capturar del
sistema USB bajo análisis. Dicho software recibe la
información permitiendo visualizarla y almacenarla en el
ordenador.
La implementación en hardware consta de tres bloques:
Capa física, Núcleo de procesamiento e Interfaz con el
ordenador (I/O), tal como se observa en la Fig. 6. La capa
física transforma las señales del par diferencial D+ y D- en
señales lógicas adecuadas para la FPGA. El segundo
bloque, que reside en la FPGA; recibe las señales lógicas
de la capa física, se sincroniza con ellas, analiza las tramas,
detecta errores y envía la información al bloque I/O. Este
último bloque es el encargado de filtrar la información
capturada del bus bajo análisis, para luego transmitir al
ordenador la información que será visualizada y
almacenada vía una interfaz paralela a USB.
Las capturas se realizan colocando el sniffer entre el
Host controller y el Device bajo estudio. Los datos
transmitidos por el sniffer pueden ser muy variados, como
por ejemplo: el número de trama, la información de los
descriptores y hasta los datos de un Endpoint byte por byte.
2.1. Capa Física
La capa física es la encargada de transformar el par
diferencial D+ y D- del bus USB bajo análisis, en las
siguientes señales: RCV, VP, VM. Las cuales poseen los
niveles eléctricos adecuados para conectarse a la FPGA.
RCV es la señal diferencia entre D+ y D-. VP y VM
corresponden a las señales del par diferencial.
Este bloque no debe cargar ni alterar al bus bajo estudio
y además debe responder a la velocidad de transmisión del
mismo (Full speed).
3. Frame number
11bits
SYNC PID
8bits8bits
CRC5 EOP
3bits5bits
Fig. 2. Paquete SOF
SYNC PID
8bits
Addr
7bits
Endp
4bits
CRC5
5bits8bits
EOP
3bits
Fig. 3 Paquete IN/OUT/SETUP
Data
0-1023Bytes
SYNC PID
8bits8bits
CRC16 EOP
3bits16bits
Fig. 4 Paquete DATA
SYNC PID
8bits8bits
EOP
3bits
Fig. 5 Paquete HANDSHAKE
2.2. Núcleo de procesamiento
El módulo de procesamiento está compuesto por una gran
cantidad de bloques independientes que trabajan en forma
sincronizada o en paralelo y están controlados por un
bloque central (Control). La mayoría de estos bloques son
máquinas de estado sincrónicas que trabajan a la velocidad
de transmisión. Un diagrama de estos bloques, se ilustra en
la Fig. 7.
Este diseño posee un reloj interno (cLKeXT), cuatro
veces más rápido que el del Host controller, que se
sincroniza con el reloj embebido en la señal RCV.
Recupera el reloj del Host y con este hace funcionar todas
las máquinas de estado que realizan la descodificación de
la trama; identificando los campos PID, SYNC, DATA,
etc. y realizando la detección de código de error.
La trama es analizada bit a bit, eliminando el bitstuffing
si lo tuviera y decodificando el NRZI, hasta obtener la
información que fue transmitida. Luego, la información es
transferida al bloque I/O para que se le apliquen los filtros
correspondientes. En el caso de que ocurra algún error
durante el proceso de descodificación, el control será
informado para que descarte la trama entera y no sean
enviados más datos al bloque I/O.
2.2.1. Control
El bloque de Control es el encargado de habilitar o de
deshabilitar las distintas máquinas de estados que integran
el núcleo de procesamiento.
Esta etapa busca la aparición del campo SYNC y cada
vez que aparece un EOP o, se produce un reset o una
desconexión del dispositivo; se redispara la búsqueda.
Luego, el bloque Control, habilita al bloque BitUnstuffer y
al almacenamiento de los próximos 8 bits en un registro de
desplazamiento. Este byte corresponde al PID y el bloque
DataType determina si el PID es válido.
Una vez detectado el PID, se procede al
almacenamiento de los restantes bits hasta que el bloque de
Status detecte algunos de los tres estadios.
FPGA
I/O
Host
controller
Device
D-
D+
Capa
Física
Núcleo de
procesamiento
FTDI245
Filtros/
Transmisión de
datos
PC
RCV VPVM
USB
Bus USB bajo análisis
Fig. 6. Esquema básico
2.2.2. PLL
Esta máquina de estados es la encargada de recuperar el
reloj a partir de la señal obtenida desde la capa física (aun
codificada en NRZI y con el bitstuffing). Utiliza como
referencia un reloj local de 48MHz (cLKeXT) para obtener
un reloj de 12 MHz (sPLLcLK) sincronizado con los datos
(RCV). El proceso PLL trabaja buscando los flancos de la
señal RCV y al encontrarlos, genera una transición en la
salida sPLLcLK. Si luego de 2 ciclos de cLKeXT no se
encuentra un flanco, se genera una transición en sPLLcLK;
en este caso los datos recibidos no cambian. En la Fig. 8 se
puede observar el diagrama de estados del proceso antes
descripto.
2.2.3. Data_Recovery
Para no provocar la aparición de estados metaestables [4]
[5], las señales VM, VP y RCV pasan a través de dos flip
flop D (filtros de metaestabilidad) que tiene como señal de
reloj sPLLcLK. Las señales libres de metaestabilidad son
VM1, VP1 y sDataIN.
2.2.4. Status
Este bloque interpreta los estados del par diferencial,
analizando los estados lógicos de las señales provenientes
del Data_Recovery (VP1 y VM1). Estos estadios están
tipificados en la especificación USB 2.0, algunos de ellos
son: E0P, Reset y Disconnect.
El estado EOP se produce cuando VP1 y VM1 se
encuentran en el nivel lógico 0 por un tiempo igual al de
dos bits de información y luego VP1 pasa a un nivel lógico
1. Esto se produce al final de cada paquete USB.
Si VP1 y VM1 se encuentran en el nivel lógico 0 por
un tiempo de 10mseg, este estadio se denomina Reset. El
Host controller coloca al bus en este estado para reiniciar a
los Devices.
El estado en el cual VP1 y VM1 se encuentran en el
nivel lógico 0 por un tiempo de 2.5useg, se denomina
Disconnect. El bus pasa a este estado cuando el Host
controller detecta que un Device se desconectó del bus.
4. Fig. 7. Diagrama interno de la implementación sobre la FPGA
2.2.5. NRZI y BitUnstuffer
La información que se transmite o recibe entre el Host
controller y los Devices, esta codificada en NRZI. Esta
codificación consiste en representar al cero con una
transición (de ‘1’ a ‘0’ ó de ‘0’ a ‘1’) y al uno con una no
transición. Por ejemplo la siguiente secuencia de bits
00000001 se codifica en NRZI como 01010100, que no es
más ni menos que el campo SYNC.
El bitstuffing consiste en insertar un cero después de 6
unos consecutivos, antes de que los datos sean codificados
en NRZI, forzando la transición de los datos cuando están
codificados en NRZI.
El bloque BitUnstuffer busca 6 unos consecutivos y le
informa al bloque Control, que el próximo bit debe ser
ignorado. Este último bloque genera una señal que
deshabilita al ShiftRegister y DataReady8, para que el
próximo bit sea extraído de la secuencia ingresada. En caso
de que el próximo bit no sea un cero, se generará una señal
de error (bitunstuffererr) que obliga al control a descartar
la trama actual y comenzar la búsqueda del paquete SOF.
2.2.6. Sync
Este bloque busca la secuencia de bits 00000001 que forma
el encabezado de todos los paquetes. Cuando la
habilitación sEnableSync se encuentra en 1 lógico, el
bloque Sync comienza la búsqueda de dicha secuencia y le
informa al Control cuando detecta dicha secuencia.
2.2.7. DataReady8 y ShiftRegister
El bloque DataReady8 es un contador de 8 bits que indica
al registro de desplazamiento, que debe asignar al bus
pData los bits de información que tiene almacenados. El
registro de desplazamiento se encuentra implementado en
el bloque ShiftRegister.
2.2.8. DataType y CRCs
El PID es un campo de 8 bits, en el cual el nibble bajo
corresponde al tipo de paquete y el nibble alto es dicho
valor complementado a uno. Por ejemplo, un paquete de
datos puede tener un PID como el siguiente: 10010110b.
5. Fig. 8. Máquina de estados PLL
El bloque DataType analiza y verifica la consistencia
del campo PID, permitiendo filtrar por tipo de paquete e
informando errores en dicho campo a través de la señal
piderr.
El PID es utilizado para determinar qué tipo de CRC
(CRC5 o CRC16) debe ser utilizado para comprobar los
errores y sobre qué campos debe calcularse. Una vez
calculado, se lo compara con el transmitido en el paquete.
Los polinomios usados en CRC5 y CRC16 son X5
+X2
+1 y
X16
+X15
+X2
+1 respectivamente.
Luego de haber recibido una señal de PID válido, los
datos ingresan al bloque CRC en forma serial para el
cálculo del código de verificación de error. Al detectar el
EOP los últimos 5 ó 16 bits anteriores son comparados con
el CRC calculado. La señal CRC_OK le indicará al bloque
TXFrame si ha ocurrido un error, para que este lo transmita
al ordenador.
2.3. Interfaz con el ordenador
Este bloque establece un vínculo bidireccional entre el
Núcleo de procesamiento y el ordenador. Dicha interfaz
recibe los filtros desde el ordenador, para luego aplicarlos
durante la captura de datos. Los filtros disponibles son:
tipo de PID, número de Endpoint y número de Device.
Además, se puede habilitar la transmisión del número de
trama e informar errores de CRC, en el caso de que
ocurran. Esta interfaz está compuesta por tres bloques y
posee dos colas, una de transmisión y otra de recepción.
La información filtrada es escrita en la cola de
transmisión por el bloque TxFrame. Una vez terminada la
trama actual se inicia la transmisión de estos datos junto
con un encabezado. La máquina de estados USB245 es la
encargada de extraer los datos de cola de salida y
escribirlos en la interfaz paralela-USB. En el caso de que la
cola se encuentre vacía, detendrá la transmisión de datos
hasta que la misma llegue a un umbral determinado. Por
otra parte, también se encarga de leer dicha interfaz,
colocando los datos recibidos en la cola correspondiente.
En la cola de recepción se encuentran los filtros de datos.
La interfaz paralela-USB está configurada en tipo de
transferencia isócrona.
3. IMPLEMENTACIÓN Y VERIFICACIÓN
El proyecto fue implementado en un kit de la compañía
Digilent (Nexys) que cuenta con una FPGA Xilinx
XC3S200-FT256. A este kit, se le conectaron dos circuitos
integrados: USB1T11A y FT245BM. El USB1T11A es la
capa física, que como mencionamos anteriormente, nos
permite obtener las señales del bus sin cargarlo. El
FT245BM fue utilizado para proveer una interfaz paralela-
USB y subir los datos obtenidos desde la FPGA hacia el
ordenador. Este dispositivo posee una transferencia
máxima de 1Mbyte/seg.
Las primeras versiones de la implementación obtenían
como único parámetro del bus, el número de trama que es
transmitido por el Host controller y generaban una señal de
detección del paquete SOF, que debía activarse cada un
milisegundo. Con esta primera etapa estabilizada y sin aun
tener la capacidad de bajar y configurar un filtro, se fijó
uno en el bloque TXFrame, para que enviase al ordenador
el número de trama y los campos PID de esa trama. Hasta
ese momento estos datos eran transmitidos al ordenador
por una interfaz RS232, la que luego sería reemplazada por
la comunicación USB que fue explicada con anterioridad.
En las etapas iniciales del desarrollo se realizaron
simulaciones del funcionamiento de cada uno de los
bloques, utilizando la herramienta ModelSim XE III 6.2c.
Se generaron dos tramas modelo para verificar el
funcionamiento global del sistema.
Se probó el funcionamiento del sniffer conectando
varios mouses, teclados y pendrives, de diversos
fabricantes, obteniendo resultados satisfactorios en la
captura de las transacciones. En la Fig. 9, se puede
observar la captura de las señales más relevantes del
sniffer, al tener conectado un pendrive Kingston al
ordenador. La captura fue realizada con un osciloscopio
Tektronix modelo TDS2014B. La señal del canal 1
corresponde a la detección del SOF (type_SOF), la del
Fig. 9. Captura del SOF con osciloscopio TDS2014B
6. canal 2 nos muestra los datos transmitidos en el bus USB
(sDataIN) y la del canal 3 corresponde a la señal anterior
decodificada en NRZI y con el bitstuffing eliminado
(sData).
En el primer flanco descendente del canal 3 comienza
el campo SYNC (00000001b), finalizando en el lugar
indicado por el primer cursor. Los cursores encierran los 8
bits correspondientes al campo PID del SOF. La secuencia
de bit que corresponden a dicho PID es la siguiente:
10100101b, que puede ser observada en el canal 3. La
misma secuencia codificada en NRZI puede ser observada
en el canal 2. A continuación de esta podemos ver el
número de trama. El tiempo de bit en la transmisión es de
83,33ns y los cursores indican 670ns, que corresponde
aproximadamente al tiempo de un byte.
En la Fig. 10 se puede apreciar los resultados de la
síntesis realizada con la herramienta Xilinx ISE 9.1.03i. El
proyecto se realizó íntegramente en VHDL.
4. CONCLUSIONES Y TRABAJO A FUTURO
Tal vez, a primera vista parezca excesivo el uso de una
herramienta como esta en el desarrollo de alguna
aplicación USB. De todos modos, resulta muy útil cuando
no es posible correr un sniffer de software (por ejemplo, un
pequeño sistema embebido en el cual no se puede ejecutar
un sniffer de software) o cuando el problema este en el
lado del hardware (por ejemplo, si se está desarrollando
sobre un FPGA a nivel lógico un Host o Device USB).
Este sniffer no analiza el protocolo de comunicación
entre el Host controller y los Hubs, así como tampoco
puede analizar el protocolo de dispositivos Low Speed y
High Speed.
La captura de los datos de un Device nos permite
conocer la forma en la que el mismo le responde al Host
controller, con lo cual, usando los datos capturados e
implementando algunas máquinas de estado podríamos
simular el funcionamiento del mismo Device.
Como trabajos a futuro queda por implementar la
verificación de ciertas condiciones de error en el bus, la
mejora en la transmisión de los datos capturados, el envió
de informes de error ocurridos en el bus y la incorporación
de una entrada de disparo externa para iniciar la captura de
datos.
Los errores del bus que esta versión del desarrollo aun
no verifica son: el caso en que el SOF no respete la
cadencia de un milisegundo, que los números de trama no
sean consecutivos y errores en el campo SYNC.
Cuando se esté analizando un bus con la totalidad del
ancho de banda ocupado, será necesaria la implementación
de otra interfaz para enviar la totalidad de los datos al
ordenador; debido a la capacidad limitada del ancho de
banda de la utilizada actualmente. Una solución a esto
seria cambiar la interfaz paralela-USB por una Ethernet.
La entrada de disparo externa resultaría muy útil para
poder determinar la latencia entre la transmisión de los
datos por parte del software y la transmisión en el bus.
La arquitectura modular del diseño permite la
incorporación de mejoras sin tener que incurrir en grandes
cambios de los bloques estables. Además, el bajo
porcentaje de ocupación de los recursos en la FPGA hace
posible la implementación de estas y otras mejoras.
5. REFERENCIAS
[1] Compaq Intel Microsoft NEC Hewlett-Packard Lucent
Philips, “Universal serial bus specification”, Revision2.0
Apri. l27, 2000.
[2] John Gamey, “An analysis of throughput characteristic of
universal serial bus,” Intel Architecture Labs, Jun. 12, 1996.
[3] Braun, F.; Waldvogel, M., "Fast incremental CRC updates
for IP over ATM networks," High Performance Switching
and Routing, 2001 IEEE Workshop on , vol., no., pp.48-52,
2001.
[4] Foley, C., "Characterizing metastability," Advanced
Research in Asynchronous Circuits and Systems, 1996.
Proceedings., Second International Symposium on , vol.,
no., pp.175-184, 18-21 Mar 1996.
[5] Wagener, P., "Metastability-a designer's viewpoint," ASIC
Seminar and Exhibit, 1990. Proceedings., Third Annual
IEEE , vol., no., pp.P14/7.1-P14/7.5, 17-21 Sep 1990.
ISE_USB Project Status
Project File: ise_usb.ise Current State: Placed and Routed
Module Name: USB • Errors: No Errors
Target Device: xc3s200-5ft256 • Warnings: 2268 Warnings
Product Version: ISE 9.1.03i • Updated: Vie 4. Ene 18:13:20 2008
Device Utilization Summary
Logic Utilization Used Available Utilization Note(s)
Number of Slice Flip Flops 189 3,840 4%
Number of 4 input LUTs 329 3,840 8%
Logic Distribution
Number of occupied Slices 198 1,920 10%
Number of Slices containing only related logic 198 198 100%
Number of Slices containing unrelated logic 0 198 0%
Total Number of 4 input LUTs 332 3,840 8%
Number used as logic 329
Number used as a route-thru 1
Number used as Shift registers 2
Number of bonded IOBs 64 173 36%
IOB Flip Flops 35
Number of GCLKs 2 8 25%
Total equivalent gate count for design 4,140
Additional JTAG gate count for IOBs 3,072
Fig. 10. Resultado de la síntesis