Compilación de código VHDL en quartus II

Mira este fragmento de código (voltear la imagen en X)

PROCESS(iCLK) 
BEGIN
  IF (rising_edge(iCLK)) THEN 
    -- Mise en mémoire du pixel
    ram(640*IdxC + PixX) <=  PIXIN; 
    -- Choix traitement
    IF (SWITCH='1') THEN
      PIXOUT <= ram(640*((IdxC + 1) mod 2) + PixX);
    ELSE
      PIXOUT <= ram(640*(2-IdxC) - PixX + 1);
    END IF; 
  END IF;   
END PROCESS;

Cuando lo compilo, el proyecto general ocupa alrededor del 15 % de los elementos lógicos y el 13 % del total de bits de memoria (QuartusII en el ciclón III). Si cambio el código a

PROCESS (iCLK)
BEGIN
  IF(rising_edge(iCLK)) THEN 
    -- Mise en mémoire du pixel
    ram(640*IdxC + PixX) <=  PIXIN; 
    -- Choix traitement
    IF (SWITCH='1') THEN
      PIXOUT <= ram(640*((IdxC + 1) mod 2) + PixX);
    ELSE
      IF (PixX > 1 AND PixX < 640) THEN
        PIXOUT <= ram(640*(2-IdxC) - PixX + 1);
      ELSE
        PIXOUT <= x"111";
      END IF;
    END IF; 
  END IF;   
END PROCESS;

yo obtengo

Error (276003): Cannot convert all sets of registers into RAM megafunctions when creating nodes. The resulting number of registers remaining in design exceeds the number of registers in the device or the number specified by the assignment max_number_of_registers_from_uninferred_rams. This can cause longer compilation time or result in insufficient memory to complete Analysis and Synthesis

Eso parece que no puedo encajar más el diseño. No creo esto. ¿Hay un error en el compilador o estoy haciendo algo mal?

Tengo la edición web Quartus II

Simplemente poniendo algunos --comentarios en las líneas como esta y compila de nuevo:

PROCESS (iCLK)
BEGIN
  IF (rising_edge(iCLK)) THEN
    -- Mise en mémoire du pixel
    ram(640*IdxC + PixX) <= PIXIN;
    -- Choix traitement
    IF (SWITCH='1') THEN
      PIXOUT <= ram(640*((IdxC + 1) mod 2) + PixX);
    ELSE
   -- IF (PixX > 1 AND PixX < 640) THEN
        PIXOUT <= ram(640*(2-IdxC) - PixX + 1);
   -- ELSE
   --   PIXOUT <= x"111";
   -- END IF;
    END IF;
  END IF;
END PROCESS;

Este código funciona con el puerto megafunción RAM 2:

PROCESS (iCLK)
BEGIN
  IF rising_edge(iCLK) THEN     
    -- Ecrire linéairement dans la RAM le pixel de la cam
    RAMWRITE <= TO_UNSIGNED(640*IdxC + PixX - 1, 11);
    -- Choix traitement
    IF (SWITCH='1') THEN
      RAMREAD <= TO_UNSIGNED(640*((IdxC + 1) mod 2) + PixX - 1, 11);
      PIXOUT <= PIXMEM;
    ELSE
      RAMREAD <= TO_UNSIGNED(640*(2-IdxC) - PixX, 11);
      IF (PixX > 1 AND PixX < 640) THEN
        PIXOUT <= PIXMEM;
      ELSE
        PIXOUT <= x"FFF";
      END IF;
    END IF;     
  END IF;                       
END PROCESS;
¿Estás absolutamente seguro de que eso es lo único que cambió en todo el diseño?
Absolutamente, simplemente poniendo algunos comentarios en las líneas como esta y compila nuevamente: PROCESO (iCLK) BEGIN IF (rising_edge (iCLK)) THEN -- Mise en mémoire du pixel ram (640 * IdxC + PixX) <= PIXIN; -- Elija el tratamiento IF (SWITCH='1') THEN PIXOUT <= ram(640*((IdxC + 1) mod 2) + PixX); DE LO CONTRARIO -- SI (PixX > 1 Y PixX < 640) ENTONCES PIXOUT <= ram(640*(2-IdxC) - PixX + 1); -- DE LO CONTRARIO -- PIXOUT <= x"111"; -- TERMINARA SI; TERMINARA SI; TERMINARA SI; PROCESO FINALIZADO;
Parece como si hubiera alcanzado alguna limitación en la herramienta de síntesis en lugar de un código VHDL defectuoso. Se decidió que no puede reconocer la RAM e inferir un bloque de RAM debido a la cláusula adicional. Para evitarlo, intente crear una variable (o señal) que sea puramente salida de RAM (no necesariamente válida), y separe la lógica para dejarla en blanco cuando lo desee, en lugar de realizar ambas tareas en una instrucción "IF" anidada. Sin embargo, debería funcionar en un solo proceso.
Edité su comentario nuevamente en la pregunta para que sea legible. Pero estoy desconcertado en cuanto a por qué este simple cambio debería hacer que el diseño "explote". Tal vez debería mostrarnos el resto del módulo en el que aparece esto.
Usted puede encontrar incluso else PIXOUT <= ram(some addr) or x"111";lo hará...
Cambié mi búfer de RAM a un tipo RAM2PORT de megafunción y cambié el proceso para incluir solo la variación de afectación de dirección (no más ram para afectar la señal) y ahora funciona. Ver mi edición para el código

Respuestas (1)

No diría que es un error, es más una limitación y, en cierto modo, tiene mucho sentido. Quiere que infiera una ram de puerto dual, el compilador quiere inferir una ram de puerto dual, sin embargo, el proceso en el fragmento de código del problema no describe correctamente la entrada de dirección del puerto de lectura de la ram, porque no todas las rutas están cubiertas, por lo que tendría que inferir un pestillo, mientras que lo que realmente quieres es que no te importe. Entonces, básicamente, le estás poniendo difícil al compilador.

Tenga en cuenta que para inferir la ram, también debe inferir algunas señales y sus valores, uno de los cuales es la entrada de dirección. En el proceso síncrono no se define el valor de esta señal inferida para el caso que termine en PIXOUT <= x"111". Por lo tanto, tendría que inferir un pestillo y la advertencia sería una incómoda "inferir pestillo en la señal de dirección inferida del carnero inferido". Termina siendo demasiado, por lo que probablemente se da por vencido, pero luego la solución alternativa no se ajusta al dispositivo. No estoy diciendo que esta sea la razón exacta por la que se está rindiendo, pero debería quedar claro que el compilador tendría dificultades para llenar los espacios en blanco para el ram inferido, dada la forma en que se codificó este proceso.

Todas las soluciones que funcionan cubren todos los casos para la señal de dirección, inferida o no. Podría probar declarando la señal y luego codificarla de la misma manera para que tenga que inferir un latch, e incluso puede compilar porque ahora al menos tendría una señal explícitamente declarada a la que puede referirse.

Los estilos de codificación para inferir bloques ram para Altera se pueden encontrar en http://www.altera.com/literature/hb/qts/qts_qii51007.pdf#page13

Esta es una de las razones por las que se recomienda encarecidamente que, si desea utilizar bloques de hardware existentes, los cree instancias como tales para evitar ambigüedades o siga los estilos de codificación apropiados para que pueda inferirse fácil y adecuadamente.

También tenga en cuenta que un simulador no tendría que lidiar con esto, porque no tendría que inferir un bloque ram per se y lidiar con el ambiguo no importa vs latch de esta señal fantasma, porque en la simulación no existe.