¿Por qué el bloque Xilinx de RAM en un Spartan-3E no devuelve datos de manera constante en un solo ciclo de reloj?

Estoy creando un diseño usando Verilog en un Xilinx Spartan-3E (XC3S500E) que usa múltiples RAM de bloque de puerto dual, todas instanciadas a través de primitivos de Verilog como RAMB16_S18_S18. Estoy usando un puerto para leer y escribir (usando la habilitación de escritura) y el segundo solo para leer (configurándolo WEBen 0). Ambos puertos comparten el mismo reloj. El bloque de RAM está configurado en 18 bits de ancho, pero estoy ignorando los datos de paridad (es decir, no uso su valor de salida y siempre escribo ceros en los bits de paridad)

Estoy usando Xilinx ISE 13.4 y sintetizando/implementando usando el flujo de trabajo de la GUI con la configuración predeterminada. (las configuraciones no predeterminadas, como la optimización de tiempo agresiva y/o la síntesis física, no tuvieron una diferencia con respecto a este problema)

Tengo restricciones de tiempo hechas para mi única red de reloj, y es consistente con la señal de reloj real que se está poniendo (la restricción es para 50 MHz, hay un reloj de 50 MHz en la placa de desarrollo que estoy usando, y el informe de tiempo indica que la frecuencia máxima para mi diseño es de 64,7 MHz. El reloj pasa por un multiplexor de reloj utilizado como habilitación de reloj, antes de pasar a la totalidad de mi lógica.

En mi código, tengo una máquina de estado que tiene tres estados (transición en el flanco ascendente del mismo reloj de 50 MHz que usa el bloque de RAM):

  1. Escriba la dirección en un registro conectado a las entradas de dirección de los puertos A y B.
  2. Lea datos, realice algunas operaciones lógicas en ellos y escríbalos en un reg[15:0]que está conectado a DIA (datos en A) en el bloque RAM (sin cambiar la dirección). Active la habilitación de escritura para el puerto A.
  3. Lea algunos pines IO en registros no relacionados. Desactive la habilitación de escritura de RAM en bloque.

Esto siempre tiene éxito en una simulación de comportamiento en ISim y (aunque tuvo menos pruebas que el simulador) siempre tiene éxito en el puerto A. El puerto B tiene una lógica idéntica (simplemente división de bits para la dirección y la misma configuración para SSR, SRVAL, INIT ) pero no logra leer durante este ciclo de reloj. Simplemente agregando un estado adicional entre 1 y 2 (dando así un tiempo de configuración de más de un ciclo de reloj completo para la dirección), el diseño funciona, aunque como estudiante de desarrollo de FPGA me gustaría saber por qué y cómo evitarlo.

De acuerdo con la hoja de datos DS312 de Xilinx y los diagramas de tiempo que contiene, esta debería ser una forma aceptable de usar el bloque de RAM. Hay tiempos de configuración y espera en esa misma hoja de datos, pero las herramientas ISE ya deberían conocerlos y aplicarlos durante el análisis de tiempo, si no me equivoco. Además, he vuelto a leer la sección de RAM en bloque de UG331 (Guía del usuario de Spartan-3 Generation) varias veces y no pude encontrar ninguna inconsistencia entre las instrucciones y mi uso de la RAM en bloque.

La lista de informes de tiempo de las rutas más lentas misteriosamente no enumera ninguna ruta que vaya al puerto RAM infractor.

Si alguien pudiera hacer una recomendación, sería apreciada, ya que he pasado bastante tiempo depurando esto y temo que podría estar cometiendo un error de principiante. Si necesita información adicional, hágamelo saber para que pueda proporcionársela.

Los BlockRAM tienen un retraso de 2 ciclos. Utilizan escritura y lectura síncronas.
@Paebbels ¿Puede mostrarme dónde dice eso en una de las hojas de datos? Es posible que me lo haya perdido, ya que todavía no soy 100% experto en tecnología FPGA y organización de hojas de datos. Además, tenía la impresión de que, de acuerdo con el diagrama de tiempo en la página 41 de la hoja de datos que vinculé (y después de una discusión en IRC), la salida estaría disponible en dos ciclos si hubiera un registro sincrónico adicional después de la salida, que no está en mi diseño.
@Paebbels También UG331: "Una operación de lectura requiere solo un borde de reloj". No estoy seguro de si se trata de algún tipo de canalización (no lo mencionan y tampoco es consistente con los diagramas de tiempo idénticos a los de la hoja de datos DS312).
Solía ​​ser el caso de que necesitaba establecer explícitamente restricciones de tiempo entre FF y BlockRams como puntos de inicio y final. Si está obteniendo resultados del próximo ciclo (BlockRams son sincrónicos como dice Paebbels, pero de una manera inusual) pero de manera inconsistente entre las ejecuciones de PAR, investigue esto. Si puedo desenterrar un archivo UCF realmente antiguo, publicaré una respuesta.
@BrianDrummond Lo investigaré. Como soy un principiante, probablemente me llevará un poco de tiempo encontrar y leer la documentación adecuada; No estoy muy familiarizado con la semántica y la sintaxis de las restricciones de tiempo que no sean las que rigen la frecuencia necesaria para un reloj y cualquier cosa sincronizada con él.
Los BlockRams son inusuales, según tengo entendido, canalizando la dirección (y escribir datos), no los datos de lectura, por lo tanto, "la operación de lectura requiere un borde de reloj". Puede presentar la dirección bastante tarde en un ciclo (por eso creo que es la dirección la que está canalizada). En el siguiente ciclo, obtiene los datos... después de un retraso sustancial (nuevamente, lo que sugiere que los datos NO ESTÁN canalizados) y en los dispositivos de esa era, necesita restricciones explícitas para que el análisis de tiempo tenga en cuenta ese retraso.
Palabras clave - Guía de restricciones: cgd.pdf; TIMESPEC DE BRAM A FF (y viceversa). (De memoria, BRAM puede ser la palabra incorrecta. La sintaxis de UCF es extraña, inconsistente, a veces distingue entre mayúsculas y minúsculas, y los errores en él se diagnostican mal, si es que se diagnostican.
@BrianDrummond Gracias. Actualmente estoy mirando la guía de restricciones en este momento.
@BrianDrummond No estoy seguro exactamente de lo que estoy restringiendo aquí. Voy de un bloque de RAM a la lógica a la dirección de entrada de otra RAM (a través de un registro). ¿Quiero una restricción de RAM de bloque a RAM de bloque, o necesito dos restricciones separadas, una de RAM de bloque a FF y la otra de FF a RAM de bloque siguiente, de modo que la suma de sus tiempos sea menor que el período-(retraso+configuración)?
Probablemente necesite BRAM a BRAM. Recuerdo vagamente configurar FF a FF, BRAM a BRAM, FF a BRAM, BRAM a FF, todo al mismo tiempo que mi período de reloj. Eso funciono. Experimente con la edición de UCF y vuelva a ejecutar el análisis de tiempo; con suerte, verá nuevas fallas.
@BrianDrummond Bien, gracias. Lo intentaré (aunque puede llevar un tiempo, mi instalación de ISE se está ejecutando en una máquina virtual lenta debido a problemas con el controlador).

Respuestas (1)

Los datos recién escritos en el flanco ascendente están disponibles directamente después de este flanco solo en el mismo puerto. En realidad, la entrada de datos se reenvía internamente a la salida de datos del mismo puerto RAM. También llamado WRITE_FIRSTmodo.

Pero nunca se reenvía a la salida del otro puerto RAM, independientemente del archivo WRITE_MODE. Estará disponible para lectura (por supuesto, en otro flanco ascendente) después de que se haya completado la escritura interna en la memoria. En su ejemplo, es solo el siguiente flanco ascendente del reloj, porque el tiempo de escritura interno siempre es más pequeño (más rápido) que el período de reloj mínimo permitido.

Este comportamiento se describe en XAPP 463 Uso de Block RAM en FPGA de generación Spartan-3 en la sección Conflictos y resolución de RAM de puerto dual. El ejemplo dado allí usa diferentes relojes, pero también se aplica cuando se usa el mismo reloj para ambos puertos.

Este comportamiento sigue siendo el mismo en los FPGA actuales de Xilinx y Altera.

El reenvío al otro puerto RAM debe realizarlo el suyo con la lógica circundante.

Esta es una pregunta bastante antigua, por lo que necesitaría ver el diseño nuevamente, pero no creo que la dirección en cuestión fuera la misma en los dos puertos.