Desajuste entre la simulación de nivel RTL y la simulación posterior a la síntesis con xilinx xst

He escrito un código verilog y la simulación RTL funciona bien. Luego de esto sinteticé el diseño utilizando la herramienta XST en Xilinx ISE 13.2. La simulación posterior a la síntesis está mostrando algunos resultados inesperados. No sé qué salió mal ya que no hubo advertencias durante la simulación. ¿Qué debería hacer ahora? ¿Hay alguna forma de depurar la lista de conexiones del nivel de síntesis posterior? ¿Cómo puedo saber qué está haciendo mi herramienta de síntesis (XST) con mi diseño? He incluido parte de mi código fuente. Es para controlar FSM de mi diseño.

always @ (posedge clock)
begin
case (state)   // s0, s1, s2, s3, s_reset are parameters
s_reset:    
        begin
            if(start_proc)
                state <= s0;
            else
                state <= s_reset;
        end
s0: begin
            pixel_value <= dataOut_bigimage;
            pixel_ref <= dataOut_smallimage;
            j <= j+1;
            if(j==1'b1)
            i <= i+1;
            if ({i,j} == 2'b11)
                if(base_col == 3'b101)
                begin
                    base_row_prev <= base_row;
                    base_col_prev <= base_col;
                    base_col <= 3'b000;
                    base_row <= base_row+1;
                end
                else
                begin
                    base_col <= base_col+1;
                    base_col_prev <= base_col;
                    base_row_prev <= base_row;
                end

            state <= s1;
        end

s1: begin
            if (pixel_value <= pixel_ref)
                accumulator <= accumulator+1;
            else
                accumulator <= accumulator;
            if({i,j} == 2'b00)
                state <= s2;
            else state <= s0;
        end

s2: begin
            if (accumulator > 2'b01)
                begin
                    matchcount <= matchcount+1;
                    rowmatch[matchcount] <= base_row_prev;
                    colmatch[matchcount] <= base_col_prev;
                end
            accumulator <= 2'b00;
            if (base_row == 2'b11)
                state <= s3;
            else 
                state <= s0;
        end

s3: begin
            task_done <= 1'b1;
            state <= s3;
        end

Todo lo que está dentro del bloque siempre es del tipo de datos reg y se inicializa correctamente en un bloque inicial separado

gracias de antemano

¿Cuál es su definición de un 'resultado aleatorio'?
@Tim, no es el mismo que obtuve en la simulación de comportamiento. Mi problema es que solo puedo monitorear los puertos de nivel superior de mi diseño después de la síntesis. Entonces, todo lo que puedo decir es que mi diseño no funciona después de la síntesis :(
No conozco ninguna "forma estándar" de depurar una lista de conexiones de síntesis posterior que no sea ponerse el sombrero de ingeniero y comenzar a trabajar hacia atrás en el diseño para ver dónde está fallando. No conozco los detalles de su herramienta, pero tal vez haya una manera de agregar redes de mantenimiento a las señales clave en su diseño y ver si se comportan correctamente. Usted dice que solo puede ver los puertos de nivel superior, ¿hay alguna razón por la que no pueda ejecutar la simulación en su lista de conexiones de síntesis y volcar la forma de onda completa?
Además, no sé si se trata de una síntesis de 50 puertas o de 500 000 puertas, pero si su proyecto es pequeño, quizás pueda agregar la fuente y alguien puede buscar problemas obvios como pestillos o posiblemente problemas de x-prop.
@Tim, la lista de redes está en términos de primitivas FPGA. Así que no puedo entender su significado. Además, no creo que haya problemas como los pestillos porque XST muestra advertencias para tales problemas. Estoy agregando la fuente aquí. A ver si alguien puede ayudar.
También podría ayudar si muestra formas de onda comparando un buen resultado de simulación con un mal resultado de simulación de síntesis, y describe exactamente qué está fallando.

Respuestas (5)

Agregue (y use) una señal de reinicio.

Los FPGA de Xilinx tienen una señal de configuración/reinicio global (GSR) que pone todos los registros en su estado predeterminado o como se especifica en la declaración de registro (esto está documentado en la Guía del usuario de XST al comienzo del capítulo 5). AFAIK, el bloque @initial se ignora.

Sin embargo, las cosas son caóticas cuando se inicia el FPGA, porque:

  • El GSR es asíncrono.
  • Los PLL no están bloqueados
  • No todos los PLL se bloquean al mismo tiempo
  • Hay condiciones de carrera en todas partes.

Entonces, los valores iniciales de Flip-Flop después del GSR no son suficientes.

Cree un módulo que genere una señal de reinicio para cada dominio de reloj. Puede crearlo haciendo AND con señales de reinicio asíncronas relevantes, como un pin de reinicio externo, señales bloqueadas de PLL/DCM, y usándolo con un sincronizador, de la siguiente manera:

Circuito de reinicio

(Fuente: ¿Cómo restablezco mi FPGA? )

Aquí hay una parte de su código que podría hacer tropezar a alguien nuevo en Verilog:

        j <= j+1;
        if(j==1'b1)
           i <= i+1;
        if ({i,j} == 2'b11)
           ...

En este código, el jutilizado para la comparación ( if(j==1'b1)) es el valor antiguo de j, no el valor recién incrementado. Pero sospecho que ya sabía esto y, de todos modos, si este fuera su problema, lo habría visto en la simulación de comportamiento (a menos que estuviera usando una asignación de bloqueo como j = j+1cuando hizo la simulación de comportamiento).

Otra cosa extraña sobre su código es que una vez que llega al estado 3, está atascado. No proporcionó ningún mecanismo para volver al estado de reinicio o al estado 0, que es un diseño inusual, pero tampoco parece ser el problema por el que está preguntando.

En realidad, es el valor anterior de j el que pretendo comparar en la declaración if. Entonces, eso no es un problema. Además, mi diseño ingresa al estado 3 cuando mi tarea está completa. Entonces se supone que debe estar atrapado allí.

Aparentemente, hay una característica específica de la herramienta que permite sintetizar bloques iniciales en su caso. Yo no era consciente de eso cuando escribí esto. Me pregunto por qué agregarían esa característica, porque solo fomentaría un mal estilo de codificación. Una megafunción de encendido y reinicio tendría más sentido. Así que toma esta respuesta como un consejo general.

Todo lo que está dentro del bloque siempre es del tipo de datos reg y se inicializa correctamente en un bloque inicial separado

Los bloques iniciales no suelen ser sintetizables. Aunque algunas herramientas pueden implementar correctamente el bloque inicial, no es recomendable confiar en este comportamiento por razones de portabilidad. Por ejemplo, si cambia de herramienta, puede romper su diseño. No debe usarlos en bloques que pretenda sintetizar en general, ya que es posible que el comportamiento previo y posterior a la síntesis no coincida.

Su bloque no tiene señal de reinicio y, por lo general, esto significa que no hay inicialización en el hardware. Para solucionar este problema, agregue una señal de reinicio y una condición de reinicio a su código. Luego, coloque el contenido del bloque inicial en el nuevo bloque de condición de reinicio.

Si bien estoy de acuerdo con su consejo sobre la síntesis de bloques iniciales, descubrí que se pueden usar con herramientas Xilinx y FPGA. Los FPGA de Xilinx pasan por una secuencia de programación y reinicio interno, y es posible inicializar registros como parte de ese proceso.
@Joe ¿Dónde descubrió que los bloques iniciales se usan durante la síntesis? Por lo que entiendo, solo se usa el valor especificado en su declaración.
@JoeHass, usar el reinicio sigue siendo la ruta preferida, porque confiar en un comportamiento específico de la herramienta como ese causa problemas de portabilidad.
@apalopohapa No podría citarte una referencia, pero enseño diseño digital usando herramientas Xilinx y algunos estudiantes usan bloques iniciales en código sintetizado, a pesar de mis advertencias de no hacerlo. Para mi sorpresa, funcionó. Creo que se debe a que los chips Xilinx generan inherentemente un reinicio de encendido global.
@trav1s Como dije originalmente, estoy de acuerdo con tu consejo. Sin embargo, decir que no son sintetizables no es estrictamente correcto.
@JoeHass ah, buen punto. Haré la edición.
@apalopohapa Lo siento, debería haber sido más específico. Que yo sepa, en un bloque inicial solo se puede realizar la inicialización de registros.

Le aconsejaría que tenga un bloque combinacional y mueva toda la lógica de control allí y solo mantenga la lógica de transferencia de datos en el bloque secuencial. No he ejecutado su código, pero siento que en el caso de que el estado sea s0, sus dos condiciones if (if j==1'b1) y (if {i,j} == 2'b11) podrían ser chocando entre sí. En una simulación de comportamiento normal, la herramienta simula el diseño sin demoras. Sin embargo, después de la síntesis, los retrasos se agregan al diseño y pueden causar el problema de "resultado aleatorio" que está viendo.

Podría estar de acuerdo con su evaluación de dividir la lógica un poco más limpiamente, pero no puedo pensar en ningún problema que pueda ser causado por las dos ifdeclaraciones que señaló. No estarían 'chocando' de ninguna manera que yo pueda ver.
He incluido muchos registros en el bloque de nivel superior simplemente definiendo registros y asignándoles valores en el bloque siempre que se muestra en el código. ese es el problema?? ¿Debo definir estos registros en módulos separados y luego instanciarlos en el bloque de nivel superior?
Estoy de acuerdo con este consejo. Tu estilo de codificación es muy peligroso. Separe la lógica combinacional en su propio bloque de procedimiento con asignaciones de bloqueo . El procedimiento cronometrado no debe hacer nada más que estado <= estado siguiente;
@JoeHass Este bloque de procedimiento es principalmente secuencial. Estoy asignando valores a los tipos de datos de registro dependiendo de alguna señal de entrada. Dividirlo significaría definir algunos módulos de registro con entradas de habilitación de carga y controlar estas señales de habilitación de carga desde este bloque. Pero entonces, ¿no será como diseñar a partir de esquemas?
@Tim, mi error. No obstante, me perdí el hecho de que OP está incrementando j.

No encontré ninguna mención acerca de que initiallos bloques son la forma correcta de inicializar el valor de los registros en la Guía del usuario de XTS .

Por otro lado, encontré la siguiente declaración en la página 109: "Dado que los bloques iniciales se ignoran durante la síntesis, solo se discuten siempre los bloques".

Bueno, parece que su herramienta de síntesis no admite la inicialización de registros en initialbloques. Tienes dos opciones:

  1. Defina una señal de reinicio adecuada y utilícela para inicializar su diseño (consulte otras respuestas para obtener explicaciones más elaboradas)
  2. Utilice la sintaxis admitida para la inicialización con restablecimiento interno (página 104):reg [3:0] arb_priority = 4'b1011;

En general, le aconsejo enfáticamente que no use initialdeclaraciones para inicializaciones de valores (excepto para la inicialización de contenidos SRAM y la inicialización de señales de banco de pruebas).