Advertencia inesperada de Verilog con respecto a la asignación de reloj FPGA

3

Tengo una pregunta sobre algo que no entiendo que está ocurriendo en mi proyecto FPGA. Necesito controlar dos dispositivos (AGC y ADC) a través de un bus SPI. Como el dispositivo maestro será el FPGA, estoy generando una señal de reloj, SCK , en código dividiendo el reloj del sistema. Luego dirijo esa señal a un cable de salida a través de un búfer de estado. A continuación se muestra mi bit de código relevante. No se muestra, pero la señal que controla el búfer de estado, en_SCK controlado por un FSM, cuando se establece bajo en estado inactivo y luego alta en el resto de los estados.

output wire SDI

   //for SCK_clock
reg SCK_gen, SCK_hold;
integer i;
reg en_SCK;
wire neg_edge_SCK;

   //SCK_generator
    always @(posedge clk)
            begin
                i <= i+1;
                SCK_hold <= SCK_gen;
                    if(i == 10)
                        begin
                            SCK_gen <= ~SCK_gen;
                            i <= 0;
                        end
            end


assign SCK = (en_SCK) ? SCK_gen : 1'bz;

Cuando consigo implementar el diseño, recibo la siguiente advertencia:

ADVERTENCIA: PhysDesignRules: 372 - Reloj cerrado. La red de reloj en_SCK_not0001 se origina    por un pin combinatorio. Esto no es una buena práctica de diseño. Use el pin CE para    controlar la carga de datos en el flip-flop.

También me doy cuenta de que mi reloj parece muy distorsionado. Pero si no uso el dispositivo triple en mi código y asigno directamente la señal del reloj al cable de salida (como en el código a continuación) obtengo una buena señal de reloj limpia.

assign SCK = SCK_gen;

A continuación se muestra una al lado de la señal SCK sin el búfer triple (izquierda) y con el búfer triple (derecha). Soy bastante nuevo en FPGA y Verilog, pero tengo entendido que usar ese estilo de código de asignación implica un búfer de estadísticas, por lo que estoy confundido por lo que parece interpretarse como una fuente de reloj cerrada (el esquema generado por XST muestra que está implícito con una puerta y . También estoy confundido acerca de cómo está distorsionando la señal del reloj. El FSM debería forzar la señal de habilitación en_SCK alta durante muchas veces el período del reloj así que no estoy seguro de lo que está sucediendo. Además, de acuerdo con el manual de la placa de demostración, otros dispositivos comparten esta señal, así que tengo que configurarla a alta impedancia cuando no está en uso. Si alguien podría apuntarme en la dirección correcta o explicarlo para mi estaría muy bien lleno. Gracias

Aquí hay un enlace a mi pregunta original en Stackoverflow.com

Aquí está el módulo completo si eso aclara las cosas. Antes solo he hecho un par de proyectos Verilog simples, así que estoy seguro de que mi código no es bueno. Pero intenté diseñarlo usando un FSM. Tal vez mi problema no sea lo que pensé. Gracias por tu paciencia.

module AGC_controller
(
    input wire clk, reset, set_AGC, AMP_DO,
    output wire SDI,  SCK,
    output reg inhibit_ADC, AMP_CS,
    //spi disable signals  ** all disabled for =1 except AD_CONV.  When AD_CONV=0, disabled.
    output wire DAC_CS, AD_CONV, SF_CEO, FPGA_INIT_B,

    output reg [7:0] led

 );

localparam [2:0]
    idle            =   3'b000,
    set_up      =   3'b001,
    start_data  =   3'b010,
    wait_for_neg=   3'b011,
    wait_4      =   3'b100,
    next_bit    =   3'b101;
//  wait_last   =   3'b110;

//signals
//for SCK_clock
reg SCK_gen, SCK_hold;
integer i;
reg en_SCK;
wire neg_edge_SCK;

initial
begin
SCK_gen = 0;
i=0;
end

//SCK_generator
always @(posedge clk)

        begin
            i <= i+1;
            SCK_hold <= SCK_gen;
                if(i == 10)
                    begin
                        SCK_gen <= ~SCK_gen;
                        i <= 0;
                    end
        end

//detect neg edge of SCK
assign neg_edge_SCK = SCK_hold & ~SCK_gen;

//general signals
reg [2:0] state_reg, state_next;
integer bit_position;
reg [7:0] AGC_buf;
reg en_SDI;

//FSM control
always @(posedge clk, posedge reset)
    begin
        if (reset)
            state_reg <= idle;          
        else
            state_reg <= state_next;
    end

//FSM next state logic
always @*
begin
    state_next = state_reg;
    case(state_reg)
        idle:
            begin
                bit_position=7;
                AGC_buf = 8'b10011001;
                en_SCK = 1'b0;
                en_SDI = 1'b0;
                AMP_CS = 1'b1;
                inhibit_ADC = 1'b0;             
                if(set_AGC)
                begin
                        state_next = set_up;
                end
            end
        set_up:
            begin
                AMP_CS = 1'b0;
                inhibit_ADC = 1'b1;
                if ((SCK_gen) && (i < 9))
                    state_next = start_data;
            end
        start_data:
            begin
                en_SDI = 1'b1;
                if ((SCK_gen == 0) && (i==2))
                    begin
                        state_next = wait_for_neg;
                        en_SCK = 1'b1;
                    end
            end
        wait_for_neg:
            begin
                if (neg_edge_SCK)
                    begin 
                        state_next = wait_4;


                    end
            end
        wait_4:
            begin
                if (i==4)
                    begin
                    //test code to light leds
                    led[bit_position] = SDI;
                        if (bit_position == 0)
                            begin
                                state_next = idle;

                            end
                        else
                            begin
                                state_next = next_bit;

                            end
                    end
            end
        next_bit:
            begin
                bit_position = bit_position - 1;
                state_next = wait_for_neg;
            end         

    endcase
end

assign SDI = (en_SDI) ? AGC_buf[bit_position] : 1'bz;
assign SCK = (en_SCK) ? SCK_gen : 1'bz;
//spi disable signals  ** all disabled for =1 except AD_CONV.  When AD_CONV=0, disabled.
assign DAC_CS = (state_reg != idle);
assign AD_CONV = (state_reg == idle);
assign SF_CEO = (state_reg != idle);
assign FPGA_INIT_B = (state_reg != idle); 

endmodule
    
pregunta Frank Dejay

2 respuestas

2

La advertencia básicamente sugiere que utilice una primitiva de reloj explícita, que por cualquier motivo no es deducida automáticamente por las herramientas.

Debe haber una referencia para su FPGA particular que indique qué primitivas están disponibles. Para un Spartan3E, por ejemplo, Xilinx UG617 describe la primitiva BUFGCE ("Búfer de reloj global con habilitación de reloj") y muestra cómo instanciarlo. Otros proveedores tendrán documentación similar.

La distorsión de su reloj probablemente se esté produciendo debido a que desordenar una línea de salida no es algo que se pueda hacer al instante. Todo lo que se está activando tiene tanto inductancia como capacitancia, por lo que incluso si el controlador puede ir alto-Z en tiempo real cero (que no puede), la red controlada continuará sonando durante algún tiempo. Si ese es un problema, necesitaría encontrar una manera de asegurarse de que la línea del reloj esté baja, y lo haya estado durante algún tiempo, antes de modificarla. En general, es probable que haya una mejor manera de lograr su objetivo, además de hacer que el reloj se apague.

    
respondido por el user572
1

Estoy de acuerdo con el usuario572 en la respuesta a tu primera pregunta, qué está causando la advertencia. Intente intencionalmente un búfer de reloj en su entrada de clk, y déjenos saber si eso borra la advertencia.

Sin embargo, creo que el extraño comportamiento de salida no tiene nada que ver con la advertencia. No puedo detectar la causa del problema, en parte porque su estilo de codificación FSM no es muy claro. No estoy seguro de si su herramienta de síntesis hará lo correcto con su código FSM o no, lo que podría ser una causa de problemas.

Para su código FSM, recomiendo los siguientes cambios:

  • Use <= en lugar de = . La diferencia podría no cambiar el significado lógico del código, pero podría llevar a diferencias entre el comportamiento simulado y el comportamiento sintetizado que será difícil de depurar.

  • Cada salida de la máquina de estado debe asignarse en cada rama del case , y para cada combinación de entradas. Confía en que los valores se mantengan constantes si no los asigna, y lógicamente eso debería suceder. Pero en síntesis, esto podría dar como resultado la creación de instancias de latches en lugar de flip-flops y no es un estilo de codificación de las mejores prácticas.

    Sí, el estilo que recomiendo es muy detallado y tedioso para escribir. El código tedioso detallado es un hecho de la vida en Verilog. Solo alegra que no estés escribiendo VHDL.

En particular, donde tiene state_next = state_reg; antes de la declaración del caso, no estoy seguro de cuál será el comportamiento resultante. Creo que te refieres a esto para crear una salida predeterminada para state_reg , si no asignas state_reg dentro de la declaración del caso. Es mejor incluir state_next <= state_next en cada rama del caso donde no desea que cambie.

Creo que, pero tendrás que experimentar para descubrir con seguridad, que la combinación del estilo de asignación de bloqueo y la sensibilidad% co_de en el bloque siempre que rodea la declaración del caso podría explicar por qué ves el comportamiento de salida defectuoso . Básicamente tienes lógica circular. En un bloque, asigna @* y en otro bloque (combinatorio) asigna state_reg <= state_next .

Lógicamente, su código significa que la asignación state_next = state_reg ocurre cuando hay algún cambio en cualquiera de las entradas del bloque con el caso. Lo que podría resultar en una condición de carrera cuando cambia state_next = state_reg , o si otra entrada cambia al mismo tiempo que un borde state_reg activa una actualización de clk . Y no está nada claro cómo se sintetizará esto.

    
respondido por el The Photon

Lea otras preguntas en las etiquetas