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.
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.
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;
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.
El orden de síntesis debe de ser del de menor al de mayor jerarquía.
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.
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.
Las principales características del bus PCI son las siguientes:
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:
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.
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.
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 |
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.
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.
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:
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.
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:
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:
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.
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:
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.
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.
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.
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.
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.
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.
Cuando el master PCI reintenta el ciclo de lectura, la interfaz PCI contesta enviando los datos almacenados en el FIFO.
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.
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.
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.
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.
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
Durante las pruebas se consiguieron mejores resultados si no se seleccionaba el casillero Map Logic to LCELLs
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.
Las opciones de síntesis con las que se lograron diseños capaces de utilizar mayores velocidades de reloj fueron:
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.
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.