Inicializar correctamente un registro de desplazamiento (Verilog)

He estado luchando con un programa Verilog muy simple. Es un registro de desplazamiento de 4 bits que gira en cada ciclo de reloj y controla cuatro LED. (Como puede ver, soy nuevo en FPAG y HDL).

El problema : el código siguiente se sintetiza sin advertencias y se programa con éxito en la FPGA. Luego, al iniciar, no pasa nada, los LED permanecen oscuros. La i_Switch_1entrada se agregó para hacer que suceda algo y, de hecho, cuando presiono el interruptor, los LED comienzan a girar.

Aquí está el código de Verilog:

Versión 1 (error)

module top
   (input i_Clk, 
    input i_Switch_1,
    output o_LED_1,
    output o_LED_2,
    output o_LED_3,
    output o_LED_4
   );

     reg [3:0]shift_reg;

     initial
         shift_reg = 4'b0001;   // has no effect

     always @(posedge i_Clk)
     begin
         shift_reg <= i_Switch_1 ? 4'b0001 : {shift_reg[2:0], shift_reg[3]};
     end

     assign o_LED_1 = shift_reg[0];
     assign o_LED_2 = shift_reg[1];
     assign o_LED_3 = shift_reg[2];
     assign o_LED_4 = shift_reg[3];

 endmodule

Evaluación : mi conclusión hasta ahora es que shift_regno se inicializa a 1. La vista RTL a continuación muestra que no se sintetiza ninguna inicialización.registro de turnos

Leí en muchos lugares que el bloque inicial es sintetizable, así que ahora estoy realmente desconcertado.

Pregunta 1 : ¿Es correcta mi evaluación?

Pregunta 2 : Suponiendo que mi evaluación sea correcta, ¿cuál es el remedio? He probado varias cosas y ninguna funciona:

  • Ruta en el pin de reinicio, pero eso no parece estar permitido.
  • Utilice una shift_reg==0comparación (versión 2 a continuación)
  • Usar una is_initbandera (versión 3 a continuación)

Estoy empezando a creer que estoy haciendo algo fundamentalmente mal. ¿¿Qué está pasando??

Versión 2 (falla)

shift_reg <= (shift_reg==0 || i_Switch_1) ? 1 : {shift_reg[2:0], shift_reg[3]}

Versión 3 (falla)

reg is_init; 
initial
    is_init = 0;   // Must have this or else the is_init gets optimized out!

always @(posedge i_Clk)
begin
    if(~is_init || i_Switch_1) begin
        is_init <= 1;
        shift_reg <= 4'b0001;
    end
    else begin
        is_init <= 1;
        shift_reg <= {shift_reg[2:0], shift_reg[3]};
    end
end

Configuración : LatticeSemi iCE40HX1K (placa nandland go) usando iCEcube2, la herramienta de síntesis es Synplify Pro.

--

Actualizar

Esto aquí funciona:

Versión 4 (éxito)

reg [3:0]shift_reg = 0;

always @(posedge i_Clk)
begin
    case(shift_reg)
    1: shift_reg <= 2;
    2: shift_reg <= 4;
    4: shift_reg <= 8;
    8: shift_reg <= 1;
    default: 
        shift_reg <= 1;
    endcase
end

Pero el resultado de la síntesis es algo inflado:registro de desplazamiento correctamente inicializado a través de una declaración de caso

¿Por qué no puedes usar reset?

Respuestas (2)

En muchos casos, las FPGA no admiten valores iniciales de encendido que no sean 0. Sé que todas las FPGA de Altera con las que he trabajado no lo hacen. De hecho, según la hoja de datos de su FPGA, este es el caso:

Cada DFF también se conecta a una señal de reinicio global que se afirma automáticamente inmediatamente después de la configuración del dispositivo.

El restablecimiento global sugiere 0, se establecería si resultara en 1.

Para evitar esto, lo que hacen algunas herramientas de síntesis es algo que se llama empujar burbujas: todo lo que debería inicializarse en 1 se inicializa en 0 y se agrega una puerta no a la salida. Sin embargo, parece que en su caso la herramienta de síntesis no está haciendo esto correctamente. De hecho, puedes probarlo manualmente si quieres:

...
shift_reg <= {shift_reg[2:1], !shift_reg[0], shift_reg[3]};
...
assign o_LED_1 = !shift_reg[0];

Aunque eso no es particularmente útil a largo plazo.

También puede probar la forma alternativa de especificar el valor inicial y ver si la herramienta de síntesis hace un mejor trabajo:

reg [3:0] shift_reg = 4'b0001;

--

De todos modos, generalmente no tendemos a confiar en un valor inicial para los registros y la lógica. En su lugar, tenemos una señal de reinicio global y cláusulas de reinicio en la lógica. Esto nos permite poder establecer todos los registros en un estado conocido en cualquier momento sin tener que hacer un ciclo de encendido.

En su ejemplo con el interruptor, parece que su código con el interruptor infirió correctamente una señal de reinicio ( R_PATsupongo) que es impulsada como se esperaba por i_Switch_1. Sin embargo, generalmente usamos un formato algo diferente para las señales de reinicio:

always @ (posedge clock) begin
    if (reset) begin
        // Do stuff here when in reset
    end else begin
        // Do stuff here when not in reset
    end
end
He estado jugando sin cesar con esto y mi conclusión es que las herramientas de síntesis de celosía (la propia de Lattice y 'Synplify') asumen que todos los DFF se inicializan como 'b0 al inicio. Eso es consistente con lo que dice la hoja de datos, como usted señala. Lo que me irrita es que un registro [3:0] r = 1'b1 se sustituye silenciosamente por un registro r = 1'b0. Ningún mensaje de ningún tipo me advierte de esto.

La declaración procesal estructurada 'inicial' no es sintetizable. Para inicializar el valor cuando su fpga se enciende, puede iniciar el valor del registro dando el valor en el momento de la declaración. p.ej.

reg [3:0]shift_reg= 4'b0000;

Intenté eso y las herramientas de síntesis a mi disposición (Lattice y "Synplify") ignoran efectivamente cualquier declaración inicial explícita o implícita. Me parece que la inicialización de registros (DFF) no se puede sintetizar así. En su lugar, tengo que construir un FSM que funcione correctamente con DFF que se inicialicen como 1'b0 en el encendido.
Estoy de acuerdo con Hesham. Esa es la razón por la que su declaración de caso funciona. La asignación en el momento de la declaración forma parte de systemverilog. Tal vez verifique los mensajes de compilación para ver si el compilador los está ignorando. Podría probar las restricciones de lugar y ruta que le permitirían establecer el estado de encendido del registro.