7. Core PCI PCITWBM

7.1. Introducción

El core PCI PCITWBM es una implementación de la interfaz PCI para ser utilizada por diseños que hagan uso del estándar Wishbone.
Su funcionamiento se puede interpretar como el de un puente entre los dos buses, el PCI [10.1.I ] y el Wishbone [10.1.M ], es decir envía y recibe datos de un bus a otro.

7.1.1. Organización del capítulo

El capítulo se encuentra organizado en las siguientes secciones:
Características del Core PCI
Características técnicas del core.
Descripción general
Breve descripción del core, diagrama de señales manejadas y ejemplo de uso.
Uso del core PCITWBM
Interfaz, parámetros y jerarquía de archivos VHDL
Interfaz PCI
Introducción a PCI, descripción de las señales PCI del core y espacio de configuración PCI.
Interfaz Wishbone
Introducción a Wishbone, descripción de las señales Wishbone del core.
Arquitectura y funcionamiento
Diagramas de bloques, funcionamiento del puente PCI-Wishbone, máquinas de estado.
Herramientas
Herramientas utilizadas y opciones de compilación.
Conclusiones
Conclusiones, mejoras y recomendaciones.

7.2. Características del core PCI

Principales características del core PCI:

7.3. Descripción general

El core PCI es una implementación del interfaz PCI para ser utilizada por diseños que hagan uso del estándar Wishbone.
Su funcionamiento se puede interpretar como el de un puente entre los dos buses, el PCI y el Wishbone, es decir envía y recibe datos de un bus a otro.

La ventaja de pasar de un tipo de bus a otro radica en que la especificación Wishbone esta pensada para interconectar diseños dentro de un mismo integrado. Las interfaces y los ciclos de transferencia de datos son iguales para todos los cores IP sin importar su función (controlador de memoria, interfaz PCI, registros, etc.) y no es necesario conocer el funcionamiento del bus PCI para hacer un diseño. Esto además de facilitar la tarea, permite la reutilización. Si ya existe un controlador de memorias con interfaz Wishbone, basta con diseñar la interconexión entre dicho controlador y el core IIE-PCI.

Fue concebido para funcionar como un dispositivo PCI target. Esto significa que el core, por si mismo, no es capaz de iniciar una transferencia en el bus PCI, sino que requiere de un dispositivo PCI master que sea el responsable de iniciar la transacción.
Esto no es una limitante ya que en la mayoría de las aplicaciones el core es utilizado como Target, siendo el CPU el que inicia las transacciones. Las lecturas y escrituras se realizan cuando la aplicación software lo requiere.

Visto del lado de la aplicación que lo utiliza, el core PCI desarrolla el rol de master Wishbone, es decir, el es capaz de iniciar una transferencia, seleccionando previamente la dirección destino de ésta.

pcitwbm_signals.jpg

7.3.1. Ejemplo de uso

Un posible ejemplo de uso de una placa PCI con memoria puede ser la aplicación de filtros a una imagen. Para llevar a cabo esto se debe transferir la imagen a una memoria en la placa, aplicar los filtros y luego leer la imagen procesada.

Existen en internet cores IP controladores de memoria con interfaz Wishbone, el core PCI también es compatible con la especificación, por lo que solo se debe diseñar una aplicación compatible con Wishbone que lea una imagen de una memoria, la procese y vuelva a escribirla. No es necesario conocer como funciona la memoria ni como se accede a ella, basta con conocer los ciclos de lectura y escritura Wishbone.

bloquesejemplocore.jpg

7.4. Uso del core PCITWBM

7.4.1. Interfaz y parámetros del core PCITWBM

El core PCI PCITWBM está escrito en VHDL. Su diseño está divido en varios bloques, el de más alta jerarquía es pcitwbm_top.

Declaración del componente pcitwbm_top

COMPONENT pcitwbm_top 
    GENERIC (vendor_id: unsigned:= X"1172"; 
             device_id: unsigned := X"ABBA";
             subsystem_id: unsigned := X"10E9"; 
             subsystem_vid: unsigned := X"10E9";
             NUMBER_OF_BARS : integer := 3;  
             BAR_0_SIZE : integer := 8192;
             BAR_0_LOW_NIBBLE: integer := 0;
             BAR_1_SIZE : integer := 8192;
             BAR_1_LOW_NIBBLE: integer := 0;
             BAR_2_SIZE : integer := 8192;
             BAR_2_LOW_NIBBLE: integer := 0;
             BAR_3_SIZE : integer := 65536;
             BAR_3_LOW_NIBBLE: integer := 0;
             BAR_4_SIZE : integer := 65536;
             BAR_4_LOW_NIBBLE: integer := 0;
             BAR_5_SIZE : integer := 65536;
             BAR_5_LOW_NIBBLE: integer := 0;
             FIFO_NUMWORDS: integer:= 14;
             LAT_TIMER_INITIAL_VALUE : integer := 7;);
    PORT(
      -- PCI 
      rstn     : IN  STD_LOGIC;
      clk      : IN  STD_LOGIC;
      irdyn    : IN  STD_LOGIC;
      idsel    : IN  STD_LOGIC;
      framen   : IN  STD_LOGIC;
      cbe      : IN  STD_LOGIC_VECTOR(3 downto 0);
      devseln  : OUT STD_LOGIC;
      stopn    : OUT STD_LOGIC;
      trdyn    : OUT STD_LOGIC;
      serrn    : OUT STD_LOGIC;
      perrn    : OUT STD_LOGIC;
      ad       : INOUT  STD_LOGIC_VECTOR(31 downto 0);
      par      : INOUT  STD_LOGIC;
      -- WB
      CLK_I    : IN  STD_LOGIC;
      DAT_I    : IN  STD_LOGIC_VECTOR(31 downto 0);
      DAT_O    : OUT STD_LOGIC_VECTOR(31 downto 0);
      ACK_I    : IN  STD_LOGIC;
      ADR_O    : OUT STD_LOGIC_VECTOR(31 downto 0);
      CYC_O    : OUT STD_LOGIC;
      RTY_I    : IN  STD_LOGIC; 
      SEL_O    : OUT STD_LOGIC_VECTOR(3 downto 0);
      STB_O    : OUT STD_LOGIC;
      WE_O     : OUT STD_LOGIC;
      CTI_O    : OUT STD_LOGIC_VECTOR(2 downto 0); 
      BTE_O    : OUT STD_LOGIC_VECTOR(1 downto 0) 
      );
END COMPONENT;

7.4.1.1. Parámetros

VENDOR_ID
Tipo: unsigned
Valor por defecto: X"1172"
Descripción: indica fabricante del dispositivo

DEVICE_ID
Tipo: unsigned
Valor: X"ABBA"
Descripción: identifica tipo o modelo del dispositivo

SUBSYSTEM_ID y SUBSYSTEM_VID
Tipo: unsigned
Valor por defecto: X"10E9"
Descripción: identifica la aplicación implementada

NUMBER_OF_BARS
Tipo: integer
Valor por defecto : 1
Descripción: número de BARs utilizados. Valores entre 1 y 6

BAR_i_SIZE
Tipo: integer
Valor por defecto : 8192 o 65536
Descripción: tamaño del rango del i-ésimo BAR. El valor debe ser una potencia de 2.

BAR_i_LOW_NIBBLE
Tipo: integer
Valor por defecto : 0
Descripción: identifica el tipo de memoria asignado al i-ésimo BAR

FIFO_NUMWORDS
Tipo: integer
Valor por defecto : 14
Descripción: profundidad de los FIFO entre la interfaz Wishbone y PCI

LAT_TIMER_INITIAL_VALUE
Tipo: integer
Valor por defecto : 7
Descripción: en caso de que el fifo de lectura se llene o el de lectura este vacío, el core espera LAT_TIMER_INITIAL_VALUE períodos de reloj e inicia un ciclo de desconexión.

7.4.2. Jerarquía de los archivos VHDL

El siguiente esquema muestra la jerarquía de los archivos .vhd que componen el core PCI.

jerarquia_archivos.jpg

El orden de síntesis debe de ser del de menor al de mayor jerarquía.


7.4.3. Recursos utilizados

A modo de comparación, se sintetizó un core con:

Para el pasaje de VHDL a EDIF se utilizó SynplifyPRO 7.0.1 y para la síntesis final Max+PlusII 10.2.

Lógica Optimización No.BAR Bits(%) LCs Max. reloj PCI Max. reloj WB
EP1K100-1 área 3 1216(2%) 1137(22%) 50.76MHz 50.76MHz
  velocidad 3 1216(2%) 1276(25%) 56.81MHz 62.89MHz
EP1K100-2 área 3 1216(2%) 1137(22%) 38.91MHz 37.73MHz
  velocidad 5 1216(2%) 1276(25%) 42.73MHz 46.29MHz

Los valores deben ser tomados como una referencia para comparar la implementación del core en cada FPGA, ya que el tamaño y velocidad final dependen fuertemente de la aplicación con la cual se sinteticen.

7.5. Interfaz PCI

7.5.1. Introducción al interfaz PCI

7.5.1.1. Historia y características principales

El estándar PCI fue definido por la empresa Intel para asegurarse de que el mercado no se vería inundado con varias arquitecturas de bus local peculiares y específicas para un cierto procesador. La primera revisión del estándar data de 1992. La última revisión (versión 2.2) se hizo disponible en 1999.

La sigla PCI significa Peripherial Component Interconnect (Interconexión de componentes periféricos). El bus PCI puede ser poblado con dispositivos, o componentes, que requieran acceso rápido entre ellos y a la memoria del sistema, y puedan ser accedidos por el procesador a velocidades que se aproximen a la de su bus local.

Resulta importante mencionar que todas las lecturas y escrituras sobre el bus PCI pueden ser realizadas como transferencias en ráfaga (burst). Al dispositivo target se le indica la dirección de comienzo y el tipo de transacción a realizar al comienzo de esta, luego se mandan datos uno tras otro, pudiendo llegarse a transferir hasta un dato por ciclo de reloj. La duración de la ráfaga la determina el master indicando si la transferencia actual es la última o no.

La siguiente figura muestra la arquitectura básica de un sistema basado en el bus PCI.

pci_system.jpg

Las principales características del bus PCI son las siguientes:

7.5.1.2. Ciclos PCI

Existe dos participantes en cada transacción sobre el bus PCI: el master y el target.
El master tiene la capacidad de iniciar una transacción. El target es accedido por el master para realizar la transacción.
Durante la documentación se usará en forma indistinta el termino ciclo o transacción PCI.

El bus PCI es un bus compartido, por lo que el master debe solicitar su uso a un arbitro antes de iniciar un ciclo. Una vez que se le concede el uso podemos identificar las siguientes fases en un un ciclo:

typical_pci_read.jpg

typical_pci_write.jpg


Fase de direcciones
Cada ciclo PCI se inicia con una fase de direcciones de duración de un período de reloj. Durante esta fase, el dispositivo master activa la señal framen para indicar el comienzo de un ciclo, coloca un comando en el bus cben (Command / Byte Enable) que identifica el tipo y coloca la dirección a la que se realiza la transacción.
Es responsabilidad de los dispositivos target registrar la dirección y el comando, ya que esta estará presente únicamente durante ese período de reloj.

Solicitud de transacción
Lo dispositivo target deben decodificar la dirección y el comando registrados y determinar si se encuentra dentro del rango de direcciones que le fueron asignadas y si es un comando soportado.
Cuando un dispositivo target determina que él está siendo accedido en una transacción, la solicita activando la señal devseln. Si ningún dispositivo la solicita, el master aborta la transacción luego de un cierto tiempo predeterminado.

Es importante notar que el master sólo indica la dirección de comienzo, y lo hace únicamente en la fase de direcciones. Al terminar la fase de direcciones, el bus se convierte en el bus de datos por toda la duración del ciclo. Es responsabilidad del dispositivo target el registrar e incrementar la dirección para apuntar al siguiente grupo de ubicaciones accedidas en las subsiguientes transferencias de datos.

Fase o fases de datos
La fase de datos de una transacción es el período durante el cual un grupo de datos es transferido entre el master y el target.
Cada fase de datos dura al menos un período de reloj PCI. Tanto el dispositivo master como el target pueden regular la velocidad de transferencia de datos, indicando si están listos para completar una fase de datos, o dicha fase debe ser extendida por más períodos de reloj. El bus pci cuenta con un par de señales (trdyn y irdyn) para este propósito.
El ancho del bus de datos es de 4 bytes, el dispositivo master puede indicar cuales de estos bytes son válidos en cada fase activando las señales del bus cben(3..0). Esto permite realizar transferencias de menos de 4 bytes.

Duración del ciclo
El master no le indica al target el número de bytes a transferir. En cambio, en cada fase de datos le indica si ese es el último dato a transferir. La señal framen es activada al comienzo de la fase de direcciones y se mantiene hasta que el master esta listo para completar la última fase de datos. Cuando el target detecta la señal irdyn activa y la señal framen desactiva en una fase de datos, sabe que esta es la última de la transacción. El master mantiene las señales en este estado hasta que el target active la señal trdyn, indicando que se llevo a cabo la última transferencia.

Fin de la transacción y retorno a estado inactivo
Cuando la última transferencia de datos se realizó con éxito, el master devuelve el bus pci a su estado inactivo desactivando la señal irdyn.
Si la posesión del bus ha sido otorgada por el árbitro a otro dispositivo maestro, este detecta que el bus ha retornado al estado inactivo al desactivarse las señales framen e irdyn.

Transferencias en ráfagas
Una transferencia en ráfaga es aquella constituida de una fase de dirección única, seguida de dos o más fases de datos. El bus master debe solicitar el control del bus únicamente antes de empezar la transacción.
La dirección de comienzo y el tipo de transacción a realizar son colocados en el bus durante la fase de dirección. Todos los dispositivos del bus deben registrar la dirección y el tipo de transacción y decodificarlos para determinar cual de ellos es el dispositivo target. El dispositivo target registra la dirección de comienzo en un contador de direcciones y es responsable de incrementar la dirección en cada fase de datos.
Un dispositivo puede ser diseñado para no soportar transferencias en ráfagas.

Las transferencias en ráfagas están compuestas de la siguiente forma:

Suponiendo que ni el master ni el target insertan tiempos de espera en cada fase de datos, la transferencia máxima es de 132 MBytes/seg para buses de 33 MHz y 32 bits. Para uno de 64 bits y 66 MHz, la transferencia máxima posible es de 528 MBytes.

7.5.1.3. Registros BAR

El PC debe configurarse automáticamente de forma que cada espacio de memoria y entrada/salida de los dispositivos PCI utilice un rango de direcciones distinto. Para poder realizar esta tarea, el sistema debe ser capaz de detectar cuanta espacio necesita el dispositivo para cada rango de memoria o entrada/salida. Para esta tarea se utilizan los BAR.

Los BAR (base address register o registros de dirección base), que forman parte del espacio de configuración, son utilizados para implementar los decodificadores del dispositivo. Cada registro ocupa 32 bits y hay 6 disponibles.

7.5.1.4. Reloj PCI

Todas las acciones realizadas sobre el bus PCI están sincronizadas con la señal de reloj clk. La frecuencia de la señal clk puede tomar cualquier valor entre 0 y 33MHz. Esto permite disminuir el consumo de energía cuando se desee, y también hacer debugging paso a paso. El core PCI puede funcionar en todo el rango de frecuencias requerido.

7.5.2. Comandos del bus PCI

Durante la fase de direcciones de un ciclo, el bus cben[3..0] es utilizado para indicar el tipo de transacción a realizar. La siguiente tabla muestra un resumen de los tipos de transacciones, y cuales ciclos son soportados. En caso de que se le solicite al core un tipo de transacción no soportado, este la ignorará.

cben[3..0] Tipo de ciclo Acción
0000 Atención de interrupción Ignorado
0001 Ciclo especial Ignorado
0010 Lectura E/S Aceptado
0011 Escritura E/S Aceptado
0100 Reserved Ignorado
0101 Reserved Ignorado
0110 Lectura de memoria Aceptado
0111 Escritura de memoria Aceptado
1000 Reserved Ignorado
1001 Reserved Ignorado
1010 Lectura de configuración Aceptado
1011 Escritura de configuración Aceptado
1100 Lectura múltiple de memoria Ignorado
1101 Ciclo de dirección doble Ignorado
1110 Lectura de linea de memoria Ignorado
1111 Lectura e invalidación Ignorado

7.5.3. Señales del bus PCI

Los señales del bus PCI pueden ser clasificadas según su tipo:

El estándar PCI define algunas señales como obligatorias y otras opcionales, a continuación se enumeran las señales del bus PCI son utilizadas por el core PCI.
Las señales activas en nivel bajo están terminadas con la letra n.

pcitwbm_signals.jpg

clk
Tipo: Entrada
Descripción: La entrada clk es el reloj del interfaz PCI. Excepto rstn (reset), todas las señales son síncronas, sus niveles son válidos solo durante el flanco de subida de reloj.

rstn
Tipo: Entrada
Nivel Activo: Bajo
Descripción: Reset. Es la señal de reset para el interfaz PCI y es asíncrona respecto al reloj. Cuando está activa, las señales de salida del bus PCI deben estar en tercer estado y las señales de colector abierto deben estar flotantes.

ad[31..0]
Tipo: Tri-estado
Descripción: Bus de direcciones/datos multiplexado en tiempo. Cada transacción consiste de una fase de dirección seguida de una o más fases de datos. Una transferencia de datos es llevada a cabo cuando irdyn y trdyn están ambas activas.

cben[3..0]
Tipo: Tri-estado
Nivel Activo: Bajo
Descripción: Command/byte enable. Este bus está multiplexado en tiempo. Durante la fase de direcciones este bus indica el comando PCI deseado definiendo el tipo de transacción a realizar; durante la fase de datos, este bus indica que byte o bytes en el bus ad son válidos.

par
Tipo: Tri-estado
Descripción: Paridad. Es el resultado de calcular la paridad de los bits bus ad y del bus cben. La paridad de los datos transferidos en una fase de datos es presentada en el flanco de reloj siguiente.

idsel
Tipo: Entrada
Nivel Activo: Alto
Descripción: La señal idsel le indica al dispositivo cuando se está realizado un ciclo de acceso a sus registros de configuración.

framen
Tipo: STS
Nivel Activo: Bajo
Descripción: Frame. La señal framen es manejada por el dispositivo master del bus en dicho instante, e indica el comienzo y la duración de una operación en el bus. Cuando framen está activa, la dirección y el comando están presentes en los buses ad y cben. La señal framen es mantenida activa durante la transferencia de datos y se desactiva para indicar el fin de un ciclo.

irdyn
Tipo: STS
Nivel Activo: Bajo
Descripción: Initiator ready. La señal irdyn es manejada por el dispositivo master del bus en dicho instante, e indica que éste puede completar la transacción de datos que se está realizando. En una transacción de escritura, irdyn indica que el bus ad tiene datos válidos. En una transacción de lectura, irdny indica que el dispositivo maestro está listo para aceptar los datos presentes en el bus ad.

devseln
Tipo: STS
Nivel Activo: Bajo
Descripción: Device select. El dispositivo target activa devseln cuando ha decodificado su dirección y solicita la transacción.

trdyn
Tipo: STS
Nivel Activo: Bajo
Descripción: Target Ready. El dispositivo target activa trdyn para indicar que puede completar la transferencia de datos que se está realizando. En una operación de lectura, trdyn indica que el target está colocando datos válidos en el bus ad. En una operación de escritura, trdyn indica que el dispositivo target está listo para aceptar datos.

stopn
Tipo: STS
Nivel Activo: Bajo
Descripción: Stop. El dispositivo target activa stopn para indicar al dispositivo master que debe terminar la transacción en curso. La señal stopn se usa en conjunto con trdyn y devseln para indicar el tipo de terminación de transacción iniciada por el target.

perrn
Tipo: STS
Nivel Activo: Bajo
Descripción: Parity Error. La señal perrn indica que hubo un error de paridad en los datos. La señal perrn es activada un ciclo de reloj después de la señal par, o lo que es lo mismo dos ciclos de reloj luego de haber ocurrido un error de paridad en el bus.

serrn
Tipo: Colector abierto
Nivel Activo: Bajo
Descripción: System Error. La señal serrn indica un error del sistema y error de paridad en la dirección. Los dispositivos pci deben activar la señal serrn si detectan un error de paridad durante una fase de transferencia de direcciones.

7.5.4. Registros de configuración PCI

Cada dispositivo lógico del bus PCI debe incluir un bloque de 64 palabras dobles (un double word contiene 4 bytes o 32 bits) para almacenar los valores de configuración. El formato de las 16 primeras palabras dobles está definido en la especificación PCI y se muestra a continuación:

pcitwbm_confreg.jpg

Los registros ocupados por las primeras 16 palabras dobles son utilizados para identificar el dispositivo, controlar las funciones del bus PCI, y proveer de información de estado.

La siguiente tabla resume las configuraciones soportadas en los registros de configuración, implementados por el core PCI:

Offset (hexa) Rango Tamaño (bytes) Tipo Nombre Interno Nombre
00 00-01 2 L vendor_id Vendor ID
02 02-03 2 L device_id Device ID
04 04-05 2 L/E P command Command
06 06-07 2 L/E P status Status
08 08-08 1 L rev_id Revision ID
09 09-0B 3 L classcode Class code
0E 0E-0E 1 L header_type Class code
10 10-13 4 L/E bar0 Base address register cero
14 14-17 4 L/E bar1 Base address register uno
18 18-1B 4 L/E bar2 Base address register dos
1C 1C-1F 4 L/E bar3 Base address register tres
20 20-23 4 L/E bar4 Base address register cuatro
24 24-27 4 L/E bar5 Base address register cinco
2C 2C-2D 2 L subsystem_vid Subsystem vendor ID
2E 2E-2F 2 L subsystem_id Subsystem ID
3C 3C-3C 1 L/E int_line Interrupt line
3D 3D-3D 1 L int_pin Interrupt pin

Referencia:
Tipo:

7.5.4.1. Registros requeridos por la especificación PCI

Registro Vendor ID
Es un registro de 16 bits que identifica el fabricante del dispositivo. Este valor se configura al sintetizar y su acceso es solo de lectura. El valor de este registro es asignado por una autoridad central (PCI SIG). El valor utilizado en el core PCI es el correspondiente a Altera (0x1172), es un parámetro del core.

Registro Device ID
Es un registro de 16 bits, asignado por el fabricante para determinar el tipo o modelo de dispositivo. El valor utilizado en el core PCI es 0xABBA, es un parámetro del core.

Registros Subsystem Vendor ID y Subsytem ID.
Este par de registros de 16 bit permite diferenciar entre dos tarjetas de usos distintos que han sido diseñadas alrededor de una misma lógica PCI. El valor de Subsystem Vendor ID es asignado por el PCI SIG, mientras que el Subsystem ID es asignado por el fabricante de la placa.

Registro Revision ID
Es un registro de 8 bits, de lectura, que identifica el número de revisión del dispositivo. Su valor es asignado por el fabricante. Puede se cambiado al sintetizar.

Registro Class Code
La función de este registro de 24 bits es Identificar la función básica del dispositivo (controlador de red, dispositivo de almacenamiento, etc.). Está divido en tres partes, el byte superior indica la clase, el medio la subclase y el inferior el interfaz de programación. El valor utilizado en el core PCI (0x0B4000) indica que es de clase "Processors" y sub-clase "Co-processor". Es de esa forma que es desplegado por los chequeos realizados por el BIOS al encender el PC y por las utilidades que dan información sobre el estado del bus PCI (lspci en Linux).

Registro Command
Es un registro de 16 bits, de escritura y lectura, que provee control básico sobre las posibilidades del dispositivo para responder o realizar accesos al bus PCI. Los bits 0 a 9 tiene asignadas funciones en la especificación PCI 2.2 10.1.I . El resto de los bits están reservados para uso futuro.

Solo los siguientes bits pueden ser modificados:

Bit Nombre Función
0 espacio de E/S habilita los accesos a E/S
1 espacio de memoria habilita los accesos a memoria
6 perrn enable habilita el reporte de errores de paridad mediante la señal perrn
8 serrn enable habilita el reporte de errores de paridad mediante la señal serrn

Los restantes bits corresponden a funcionalidades de PCI Master y ciclos no soportados.

Registro Status
Este registro de 16 bits mantiene el estado del dispositivo PCI.
El registro puede ser leído normalmente, pero la escritura se maneja de forma diferente. En una escritura, el bit que está activo se desactiva mediante una escritura de un 1. No es posible activar un bit por software.
Este método fue elegido para simplificar el trabajo del programador. Luego de leer el Status y hacerse cargo de los errores correspondientes, el programador desactiva los bits escribiendo el valor que había sido leído en primera instancia. De esta forma, si algún otro bit cambió durante el proceso, este es preservado.

El significado de los bits del registro de estado implementados por el core PCI es el siguiente:

Bit Nombre Condición de activación
11 target abort señalado dispositivo abortó una transacción
14 system error señalado dispositivo activó la señal serrn
15 error de paridad error de paridad detectado

Registro Header Type
El bit más alto de este registro indica si el dispositivo es multifunción. El resto de los bits indican el tipo de cabezal de configuración que se está especificando. Todas las descripciones realizadas hasta ahora corresponden al cabezal de tipo 0, y es el usado por la mayoría de los dispositivos PCI. Existen otros tipos definidos para puentes PCI-PCI, etc.

7.5.4.2. Registros opcionales implementados

Registro Interrupt Pin
Este registro es requerido si el dispositivo es capaz de de generar pedidos de interrupción.
Determina cual de los cuatro pines de pedido de interrupción PCI está conectado al dispositivo. En el estado actual del core PCI no se utilizan interrupciones, por lo tanto su valor está asignado a 0.

Registro Interrupt Line
Este registro de lectura y escritura es requerido si el dispositivo es capaz de de generar pedidos de interrupción. Se utiliza para identificar a que entrada del controlador de interrupciones está conectado el pin indicado por el registro Interrupt Pin.

Registros BAR (Base Address Register)
Al menos un registro de este tipo es requerido si el dispositivo memoria y entrada/salida. Estos registros son utilizados para determinar los requerimientos de tamaño y cantidad de rangos de direcciones de memoria y entrada/salida deben ser asignados al dispostivo.

El bit más bajo del registro es solo de lectura y determina si el rango de direcciones corresponde a memoria (0) o entrada/salida (1). El valor de los restantes bits del registro depende del bit 0 y se muestra en el siguiente diagrama:

bartypes.jpg

En el momento de inicialización, el sistema escribe unos en cada registro y luego los lee para obtener la información de cantidad y tamaño solicitados por el dispositivo. Si el valor leído es 0, esto significa que el BAR no está implementado. Si el valor no es 0, la posición del primer 1 contando a partir del bit menos significativo del campo Base Address (ver diagrama anterior) determina el tamaño de memoria o entrada/salida. Luego, el sistema escribe en el BAR la dirección de comienzo del rango asignado.

Ejemplo:
El sistema escribe 0xFFFFFFFF en el BAR0 y lee el valor 0xFFF00000. Como el valor es distinto de 0, significa que el BAR está implementado. La información obtenida es la siguiente:

7.6. Interfaz Wishbone

Es un requerimiento para el uso del core PCITWBM tener un conocimiento básico del interfaz Wishbone, pero no es necesario conocer los detalles de funcionamiento del interfaz PCI.

7.6.1. Introducción al interfaz Wishbone

La interfaz Wishbone es una especificación que define un método de interconexión de diseños digitales dentro de un circuito integrado.

La arquitectura Wishbone resuelve un problema básico en el diseño de circuitos integrados, que es cómo conectar circuitos entre sí de una manera simple, flexible y transportable. Los circuitos a los que nos referimos proveen alguna funcionalidad específica, y generalmente son distribuidos como cores IP (Intellectual Property Cores, o núcleos de propiedad intelectual), que pueden ser adquiridos o desarrollados.
Los IP cores son, entonces, los bloques funcionales que forman parte del sistema. Generalmente son desarrollados independientemente, y el hacerlos trabajar juntos resulta problemático. El interfaz Wishbone estandariza los interfaces utilizados por IP cores, lo que simplifica su interconexión para la creación de sistemas a medida sobre un chip (SoC).

La especificación Wishbone pertenece al dominio público, puede ser libremente copiada y distribuida, y utilizada para el diseño y producción de componentes de circuitos integrados sin necesidad de pagar ningún tipo de licencia o royalties.

En el apéndice "Interfaz Wishbone" se hace una descripción más detallada del funcionamiento del bus Wishbone.

7.6.1.1. Interconexión maestro/esclavo

Wishbone utiliza una arquitectura maestro/esclavo, lo que significa que aquellos módulos con interfaz maestro inician las transacciones de datos realizadas con los módulos esclavos.

El esquema de interconexión de módulos puede adaptarse de acuerdo a la función que estos cumplen y el uso final que se les de. Puede tenerse una conexión única entre 2 módulos, conexiones tipo bus donde todos los master pueden iniciar transacciones con todos los esclavos, encadenar varios módulos maestro/esclavo, etc.

Algunos ejemplos de conexiones:

interconexionwishbone.jpg

Wishbone permite que el integrador del sistema ajuste esta interconexión según las necesidades de intercomunicación entre los módulos que desea interconectar. Esto es posible ya que la especificación esta pensada para ser utilizada dentro de circuitos integrados donde la lógica reconfigurable y los chips de circuitos integrados tienen caminos de interconexión que pueden ser ajustados o diseñados según las necesidades.

En el apéndice "Interfaz Wishbone" se puede encontrar una descripción más detallada.

7.6.2. Señales del interfaz Wishbone

A continuación se describen las señales del interfaz Wishbone utilizadas por el core PCI. Todas las señales son activas por nivel alto y la terminación _I y _O indica si son entradas o salidas al core respectivamente.

CLK_I
Tipo: Entrada
Descripción: Reloj. La señal de reloj coordina todas las actividades para la lógica dentro de un dispositivo Wishbone. Todas las señales de salida Wishbone son registradas en el flanco de subida de CLK_I. Todas las entradas Wishbone deben estar estables antes del flanco de subida de CLK_I.

DAT_I[31..0]
Tipo: Entrada
Descripción: El bus DAT_I es la entrada de datos. Su ancho de palabra es de 32 bits.

DAT_O[31..0]
Tipo: Salida
Descripción: El bus DAT_O es la salida datos. Su ancho de palabra es de 32 bits.

ACK_I
Tipo: Entrada
Descripción: Acknowledge Input. La señal ACK_I le indica al dispositivo master que se ha realizado una transferencia en forma exitosa.

ADR_O[31..0]
Tipo: Salida
Descripción: El bus ADR_O es manejado por el master y e indica la dirección de los datos que deben leerse o escribirse.

CYC_O
Tipo: Salida
Descripción: Cycle Output. La señal CYC_O indica que un ciclo válido está en progreso. La señal se mantiene activa por la duración de todo el ciclo. Por ejemplo, en una transferencia en bloque, la señal CYC_O se activa en la primer transferencia y se mantiene activa hasta la última.

RTY_I
Tipo: Entrada
Descripción: Retry Input. Indica que el interfaz no esta listo para aceptar o enviar datos, y que el ciclo debe ser reintentado más tarde. En este caso, el core PCI interrumpe el ciclo Wishbone y vuelve a comenzar un nuevo ciclo para terminar la transferencia de datos.

SEL_O[3..0]
Tipo: Salida
Descripción: Select Output. El bus SEL_O indica qué bytes del bus DAT_O contienen datos válidos, o en que bytes del bus DAT_I se esperan datos válidos. Estas señales se corresponden con las señales del bus PCI cben.
STB_O
Tipo: Salida
Descripción: Strobe Output. La señal STB_O indica un la presencia de un dato válido en DAT_O en un ciclo de escritura o que esta listo para recibir datos en un ciclo de lectura. El dispositivo esclavo Wishbone debe responder con alguna de las señales ACK_I o RTY_I frente a cada activación de la señal STB_O.

WE_O
Tipo: Salida
Descripción: Write Enable Output. La señal WE_O indica si el ciclo de bus corresponde a una lectura o a una escritura. La señal se activa durante los ciclos de escritura y se desactiva en los ciclos de lectura.

CTI_O[2..0]
Tipo: Salida
Nivel Activo: Alto
Descripción: Cycle Type Identifier. La señal CTI_O provee información adicional sobre el ciclo que se está realizando. Es parte de la especificación de Wishbone avanzado. El master le envía esta información al esclavo y este debe usarla para preparar la respuesta a dar en el ciclo siguiente.
La siguiente tabla muestra los posibles tipos de ciclos:

CTI_O[2..0] Descripción
000 Ciclo clásico
001 Ciclo burst de dirección constante
010 Ciclo burst con incremento de direcciones
111 Fin del ciclo burst

BTE_O[1..0]
Tipo: Salida
Descripción: Burst Type Extension. La señal BTE_O provee información adicional sobre el ciclo que se está realizando. Esta información es relevante únicamente para ciclos burst con incremento de direcciones.
En la implementación del core PCI se incluye, ya que es mandatoria en la especificación Wishbone si se desea utilizar CTI_O, pero su valor es siempre 00. Esto significa que si se utilizan ciclos burst con incremento de direcciones, su incremento es lineal.

7.7. Arquitectura y funcionamiento

7.7.1. Arquitectura

El diseño se dividió en varios bloque para facilitar el diseño y prueba.

pcitwbm_bloques.jpg

CONTROL0
Instancia de entidad blk_control.
Bloque principal de control. Realiza el control general de todo el funcionamiento del core y también contiene multiplexores para enviar direcciones y datos hacia el interfaz Wishbone.
AD0
Instancia de entidad blk_ad.
Bloque de interfaz con las señales AD del bus PCI. Se encarga de leer y escribir las señales de direcciones y datos del bus PCI.
PAR0
Instancia de entidad blk_par.
Bloque de paridad. Realiza el cálculo de paridad, ya sea de los datos leídos, así como de los enviados por el bus PCI.
CBE0
Instancia de entidad blk_cbe.
Bloque de comando o de habilitación de bytes. Registra los comandos y las señales de habilitación de bytes del bus PCI y las mantiene disponibles para su uso posterior.
CONF_REG0
Instancia de entidad blk_conf_reg.
Bloque de registro de configuración PCI. Almacena los registros de configuración PCI del dispositivo.
WB_REG0
Instancia de entidad blk_wb_reg.
Bloque de registro de mapeo de direcciones a espacio Wishbone.
TRANS2PCI
Instancia de entidad blk_add_trans.
Bloque de transformación a espacio PCI. Realiza el mapeo de direcciones Wishbone a direcciones PCI.
TRANS2WB
Instancia de entidad blk_add_trans.
Bloque de transformación a espacio Wishbone. Realiza el mapeo de direcciones PCI a direcciones Wishbone.
DATI_MUX
Instancia de entidad blk_dati_mux.
Bloque multiplexor de datos. Realiza la multiplexión de datos a escribir en el bus PCI. Permite leer datos de cualquiera de los registros de configuración (CONF_REG0 y WB_REG0) y los datos provenientes del bus Wishbone.
PCIW_FIFO
Instancia de entidad fifo.
Bloque de buffer FIFO para escritura hacia Wishbone. Permite que el reloj utilizado por la aplicación a conectar a través del interfaz Wishbone utilice una frecuencia de reloj diferente a la utilizada por el bus PCI.
PCIR_FIFO
Instancia de entidad fifo.
Bloque de buffer FIFO para lectura desde Wishbone. Permite que el reloj utilizado por la aplicación a conectar a través del interfaz Wishbone utilice una frecuencia de reloj diferente a la utilizada por el bus PCI.
PCIR_FIFO_DEMUX
Instancia de entidad blk_fifo_demux.
Bloque demultiplexor del FIFO de lectura desde Wishbone. Realiza la tarea de separar las direcciones de los datos leídos que se envían a través del fifo.
WB_INTERFACE
Instancia de entidad blk_wb_interface.
Bloque de interfaz con Wishbone. Implementa el protocolo de comunicación Wishbone.

7.7.2. Puente PCI-Wishbone

La mayoría de las interfaces PCI existentes resuelven parte de la comunicación con el bus PCI, la interfaz de aplicación tiene señales que deben ser controladas para responder a ciclos en el bus PCI. Esto hace que el diseñador de la aplicación deba conocer el protocolo PCI para implementar exitosamente un diseño.

Como solución a esto se optó por diseñar un modulo que provee una interfaz de aplicación más sencilla (Wishbone), cuyo comportamiento no dependa mayormente de lo que sucede en el bus PCI, sino solo si ocurre una escritura o una lectura desde el bus PCI.
Esto se logra con un módulo puente entre el bus PCI y la aplicación. El modulo se encarga de manejar las señales del bus PCI para recibir los datos o enviar datos y por otro lado maneja las señales de la interfaz wishbone para enviar los datos recibidos o solicitar los datos pedidos desde el bus PCI.

Como se decidió implementar un core PCI target, las transacciones son empezadas solo desde el bus PCI, no desde el lado Wishbone del core. Por esta razón la interfaz Wishbone es un interfaz maestro.

7.7.2.1. Funcionamiento del puente PCI-Wishbone

Cuando un master PCI realiza una escritura dentro de los rangos de direcciones asignados al core PCI, este acepta los datos y los almacena en un FIFO.

PCIWB_WR1.jpg

Luego al detectar que el FIFO de escritura no esta vacío, la interfaz Wishbone realiza tantos ciclos de escritura como sean necesarios hasta vaciar el FIFO.

PCIWB_WR2.jpg

Cuando un master PCI comienza una lectura dentro de los rangos de direcciones asignados al core PCI, este registra la dirección de comienzo y responde pidiendo un retry, esto hace que el master PCI aborte el ciclo y vuelva a intentar nuevamente la lectura cierto tiempo después.
Mientras esto sucede la interfaz Wishbone realiza ciclos de lectura, almacenando los datos leídos en el FIFO de lectura hasta llenarlo.

PCIWB_RD1.jpg

Cuando el master PCI reintenta el ciclo de lectura, la interfaz PCI contesta enviando los datos almacenados en el FIFO.

PCIWB_RD2.jpg


7.7.2.2. Detalles de la escritura al core PCI.

En caso de querer comenzar un ciclo de escritura PCI a una dirección asignada al core PCI, si la interfaz Wishbone no ha vaciado el FIFO de escritura, el core solicita un retry al master PCI.
Si ya se estaba realizando un ciclo de escritura y el FIFO de escritura se llena, se insertan tiempos de wait en el bus PCI (trdyn='1') para dar tiempo al master Wishbone a sacar datos del FIFO. Si transcurrido 8 períodos de reloj el FIFO aún no se ha vaciado se pide un disconect without data lo que provoca que el ciclo se corte. Si aún restaban datos por escribir el master PCI automáticamente comenzará otro ciclo de escritura.

Si la aplicación del lado Wishbone que recibe los datos escritos por el core esta mal implementada o no responde a las escrituras, el bus PCI podría quedar trancado pues se estarían intentando escrituras PCI continuamente y el FIFO nunca se encontraría vacío.

7.7.2.3. Detalles de la lectura al core PCI.

Cuando se realiza una lectura a una dirección asignada al core PCI, este chequea si hay datos en el FIFO de lectura y si corresponden a la dirección solicitada. En caso de coincidir las direcciones, se transfieren los datos desde el FIFO hasta que se vacíe o el ciclo sea finalizado por el master PCI.
En caso de que el FIFO de lectura se vacíe, se insertan tiempos de espera en el bus PCI (trdyn='1') para dar tiempo a que el master Wishbone coloque más datos en el FIFO de lectura. Si transcurridos 8 períodos de reloj no hay nuevos datos en el FIFO de lectura se pide un disconnect without data lo que provoca que el ciclo se corte. Si aún restaban datos por leer el master PCI automáticamente comenzará otro ciclo de lectura.
Si lo datos almacenados en la boca del FIFO de lectura no corresponden con la dirección solicitada, se registra la nueva dirección, se vacía el fifo y se vuelve al comienzo del proceso, solicitando un retry al master PCI.

7.7.3. Registro de traslación de direcciones

La dirección asignada a cada BAR del core PCI es asignada automáticamente en el momento de inicio del PC, y puede variar, dependiendo del PC que se esté utilizando y de cuantos dispositivos PCI estén colocados en el bus.

Para facilitar la tarea de diseño y decodificación de direcciones dentro de la aplicación en el bus Wishbone se implementaron registros de traslación de direcciones.
La función de los mismos es lograr que un acceso PCI a una dirección dentro del rango correspondiente a un BAR determinado se refleje como un acceso siempre a la misma dirección del bus Wishbone.

Estos registros pueden leerse y escribirse a través del BAR0 del core PCI en las direcciones indicadas por la siguiente tabla:

Registro de traslación Ubicación en BAR0 Valor luego de Reset
para Bar 1 0x10 0x10000000
para Bar 2 0x14 0x20000000
para Bar 3 0x18 0x30000000
para Bar 4 0x1C 0x40000000
para Bar 5 0x20 0x50000000
para Bar 6 0x24 0x60000000

Supongamos que al momento del booteo se le asigna a BAR0 el valor 0x80000000 y a BAR1 el 0x8F000000.
Si se quiere que los accesos al rango de direcciones correspondiente a BAR1 se mapeen a direcciones Wishbone que comiencen a partir de la dirección 0xE0000000, se debe escribir ese valor en la dirección 0x80000010.
Si se realiza una escritura a la dirección PCI 0x8F001000, se estará escribiendo en la dirección Wishbone 0xE0001000.

7.7.4. Independencia de relojes PCI y Wishbone

Los FIFOs entre la interfaz PCI y la interfaz Wishbone, no solo sirven como almacenamiento intermedio de los datos, sino que al contar los FIFOs con entradas de reloj independientes para la lectura y la escritura, permiten que las lógicas de las interfaces funcionen con diferentes velocidades de reloj.


7.7.5. Maquina de estado de Target PCI

state_main.jpg

El core detecta el comienzo de una transacción PCI cuando framen es 0 en un flanco de subida de reloj. En ese momento se latchean las direcciones y el comando que identifica el tipo de ciclo. Con esta información se pasa al estado correspondiente según se indica en el diagrama. Más abajo se muestran los ciclos de cada una de las posibilidades.
En caso de que el ciclo no sea para este dispositivo, o se intente realizar una transacción no soportada, el core pasa al estado bus_busy hasta que termina esa transacción.

state_conf_read.jpg

7.7.5.1. Conf Read

Al realizar un acceso a los registros de configuración se espera hasta que el master esté listo para recibir los datos, se transfieren los datos y luego se pasa a un estado de turn arround mediante el cual se libera el bus de acuerdo a lo especificado en el estándar.

7.7.5.2. Wishbone Conf Read

En BAR0 se encuentran mapeados los registros de traslación de direcciones PCI a Wishbone. No está permitido realizar lecturas burst a estos registros, por lo que en dicho caso, se realiza una desconexión sin transferencia de datos. En un acceso simple, se espera a que el master esté listo a recibir los datos, se transfieren los datos y luego se pasa a un estado de turn arround mediante el cual se libera el bus de acuerdo a lo especificado en el estándar.

state_conf_write.jpg

7.7.5.3. Conf Write

Al realizar una escritura a los registros de configuración, se espera a que el master ponga el dato válido en el bus, se lee y luego se pasa a un estado de turn arround mediante el cual se libera el bus de acuerdo a lo especificado en el estándar.

7.7.5.4. Wishbone Conf Write

De igual forma que en Wishbone Conf Read, no está permitido realizar escrituras burst a estos registros. El resto de los estados son similares a Conf Write.

state_pci_read.jpg

7.7.5.5. Pci Read

Si la dirección solicitada en la lectura PCI no coincide con la presente en la boca del pcir_fifo (que transfiere datos desde Wishbone a PCI), se realiza una desconexión sin transferencia de datos y el master realizará un reintento de lectura en un instante posterior.
Si la dirección solicitada en la lectura PCI coincide con la presente en la boca del pcir_fifo, se pueden empezar a realizar transferencias. Para esto se espera hasta que el master esté listo para recibir los datos y luego, se transfieren datos ya sea uno solo o en burst.
Si en algún momento de la transacción el pcir_fifo se encuentra vacío, se espera una cierta cantidad de períodos (configurable por el usuario) para dar tiempo a que Wishbone cargue datos. Si no se cargan datos durante ese tiempo, se realiza una desconexión sin transferencia de datos.

state_pci_write.jpg

7.7.5.6. Pci Write

En una transacción de escritura, el core acepta los datos cuando el pciw_fifo está vacío. Si la aplicación Wishbone es más lenta que el bus PCI, el fifo se completa y se pasa a un estado de espera, que puede terminar por timeout en un disconnect without data (que el master reintentará nuevamente más tarde). Si la aplicación vacía el pciw_fifo antes, se continúa la transacción. En la última transferencia de datos se pasa a un estado de turn arround mediante el cual se libera el bus de acuerdo a lo especificado en el estándar.


7.7.6. Maquina de estado de Master Wishbone

state_wb_main.jpg

Cuando la interfaz PCI del core acepta una transacción, coloca en el pciw_fifo un comando que le indica al bloque Wishbone que operación debe realizar y la dirección de comienzo. Se puede realizar entonces una lectura o una escritura.

state_wb_read.jpg

7.7.6.1. Wishbone Read

Se realizan ciclos de lectura por el interfaz Wishbone hasta que se realice la última lectura en el lado PCI. En caso de que se llene el pcir_fifo, se pasa a un estado de espera hasta que desde PCI se vacíen los datos, o se termine la transacción.
En caso de que un dispositivo solicite un retry se corta el ciclo Wishbone y se reintenta un nuevo ciclo de lectura un ciclo de reloj después.

state_wb_write.jpg

7.7.6.2. Wishbone Write

Se espera hasta que el pciw_fifo contenga datos, y en ese momento se pasan a realizar escrituras Wishbone. Si un dispositivo Wishbone solicita un retry, se vuelve a intentar un ciclo de reloj más tarde. Si el dato es el último, se escribe el dato y se vuelve al estado de espera.
Si se vacía el pciw_fifo, se pasa a un estado de espera hasta que aparezcan datos nuevamente o se salga por un disconnect without data.


7.7.7. Detalles de implementación

7.7.7.1. Codificación one-hot

Para alcanzar mayores velocidades de reloj, y simplificar la lógica de transición de estados se utilizó la técnica de "one-hot" para codificar los estados.
Esta técnica consiste en utilizar un flip-flop por estado y solo vale '1' la salida del FF del estado activo.

El software SynplifyPRO puede codificar los estado automáticamente. La declaración de los estados y la configuración de atributos para ello se muestran a continuación:

TYPE state_type IS
        (state1, state2, state3, state4);
SIGNAL state, nxstate : state_type;
-- ONE HOT PARA SYPLICITY
ATTRIBUTE syn_encoding : string;
ATTRIBUTE syn_encoding OF state : signal IS "onehot";

La asignación de variables final es:
state1: 0001
state2: 0010
state3: 0100
state4: 1000

7.7.7.2. Salidas registradas.

Todas las salidas del core PCITWBM están registradas, esto asegura que están libres de espurios.
Otro beneficio de esto es que evitan largas cadenas de lógica combinatoria lo que deteriora la performance del diseño.

7.8. Herramientas

7.8.1. VHDL a EDIF

El software sintetizador Max+PlusII soporta un sub-conjunto de VHDL muy limitado y los mensajes de error no son claros, lo que hace el trabajo muy difícil.
Ante esta situación se optó por utilizar algún software de síntesis que a partir de archivos VHDL generara archivos EDIF.
Los archivos EDIF son un estándar de la industria para el pasaje de diseños entre programas.
El software utilizado fue SynlifyPRO 7.0.1 de Synplicity (http://www.synplicity.com)

Durante las pruebas se consiguieron mejores resultados si no se seleccionaba el casillero Map Logic to LCELLs

simplify.jpg

Esta opción genera un EDIF con lógica mapeada a la estructura del FPGA en el que se va a sintetizar el diseño. Al no seleccionarse, solo se genera un archivo de nodos optimizado y el Max+PlusII se encarga finalmente de mapear la lógica a los recursos del FPGA de mejor forma.

7.8.2. Sintetizador

Una ves generado el EDIF se crea un proyecto con el archivo, automáticamente el Max+PlusII identifica que el archivo fue creado con SynlifyPRO.

Las opciones de síntesis con las que se lograron diseños capaces de utilizar mayores velocidades de reloj fueron:

7.8.3. Simulador

Para las simulaciones se utilizó el simulador incluido en el software Max+PlusII.

7.9. Conclusiones

El objetivo de diseñar e implementar un core PCI en lenguaje VHDL fue alcanzado.

La elección del interfaz Wishbone para la comunicación con otros cores fue acertada, ya que se comprobó que es sencilla de utilizar.

El haber implementado únicamente el funcionamiento como target PCI permite que el tamaño del core sea pequeño dejando recursos del FPGA disponibles para implementar las aplicaciones. En caso del FPGA utilizado en la placa IIE-PCI, utiliza menos de una cuarta parte de los recursos.

A diferencia de la mayoría de los cores existentes, esta implementa un puente entre PCI y Wishbone. Por lo que para hacer uso de este no es necesario conocer el protocolo de comunicación PCI, sino solo el wishbone que es un estándar de comunicaciones entre cores IP, sin importar las funcionalidades que implementen.

El punto más débil del core PCI es la falta de un test bench exhaustivo. Debido a limitaciones de tiempo no se pudo implementar.

7.9.1. Modificaciones y recomendaciones

La principal modificación recomendada es la implementación de interrupciones. En el estado actual, la única forma de saber el estado de la aplicación sintetizada en la placa es utilizando polling.

La escritura del código VHDL del core fue un proceso de aprendizaje. Esto se distingue al comparar las primeras líneas de código escritas con las últimas. Sería interesante escribir nuevamente algunas partes con el conocimiento adquirido de modo de poder mejorar la frecuencia máxima de funcionamiento y optimizar el área ocupada al sintetizarlo.

Otra prueba interesante sería la de compilar y probar el core PCI en otro FPGA, incluyendo la posibilidad de sintetizarlo con las herramientas de Xilinx.