Mux de 32 vías produce problemas de tiempo horribles

3

Estoy codificando un mux de 32 vías en verilog.

La entrada es un contador que cuenta de 0 a 31, incrementando cada ciclo de reloj. Cada valor de contador selecciona una porción diferente de un vector como salida.

En mi proceso de máquina de estado, el contador se genera de la siguiente manera:

    // Complicated stuff!
    if (counter < C_NUM_CYCLES-1) begin
       counter       <= counter + 1;
    end

Utilizando el recuento, selecciono un segmento de 32 bits de un vector de 1024 bits. La entrada 0 selecciona los 32 bits LS del vector, 1 selecciona los siguientes 32 y así sucesivamente. Esta porción se genera en un proceso cronometrado separado:

    S1_input_val <= 1;
    S1_input     <= input_vector_i[(counter_z[0]+1)*(C_S1_INPUT_LENGTH)-1 -: C_S1_INPUT_LENGTH];

Esta señal de 32 bits se usa en otra entidad que deseo usar para procesar el número completo de 1024 bits, un segmento de 32 bits a la vez.

Funciona perfectamente bien en simulación. La implementación produce un horrible informe de tiempos:

                                    Delay   Cumulitive
CARRY4 (Prop_carry4_CI_CO[3])   (r) 0.117   6.879   Site: SLICE_X54Y3   counter_reg[12]_i_1/CO[3]
CARRY4 (Prop_carry4_CI_CO[3])   (r) 0.117   6.996   Site: SLICE_X54Y4   counter_reg[16]_i_1/CO[3]
...
CARRY4 (Prop_carry4_CI_CO[3])   (r) 0.114   39.719  Site: SLICE_X55Y148 counter_reg[1016]_i_1/CO[3]
CARRY4 (Prop_carry4_CI_O[1])    (r) 0.334   40.053  Site: SLICE_X55Y149 counter_reg[1020]_i_1/CO[3]
Arrival Time                                40.053  <- ns!

Este problema permanece incluso después de agregar varias etapas de registro y todo se está ejecutando en procesos cronometrados. Parece que solo el mecanismo de selección de mux generado por las herramientas está causando esto. No sé cómo puedo ingresar para agregar etapas de registro.

¿Esto es solo una limitación inherente del hardware, o hay un problema con mi mux y la forma en que lo estoy implementando? puedo hacerlo mejor? ¿Cómo puedo mejorar el tiempo?

Una de las cosas más importantes que me desconcierta es cuál es la señal a la que se hace referencia como counter_reg en el informe de temporización. Sube a 1024, mientras que el contador real solo sube a 32. He pasado un tiempo investigando en el editor de FPGA pero no he tenido mucho éxito.

La herramienta es Vivado 2014.1.

Editar:

Pensé que tal vez las señales que iban a la siguiente entidad no se estaban registrando lo antes posible. Ese no es el caso, este es el código en el extremo receptor de las entradas:

// Register in inputs
always@(posedge clk) begin        
    if(rst) begin
      vector_i     <= 0;
      vector_val_i <= 0;
    end 
    else begin
      if (input_vector_val == 1) begin
          vector_i     <= input_vector;
          vector_val_i <= input_vector_val;
      end
      else begin
          vector_i     <= 0;
          vector_val_i <= 0;
      end
    end
end 

Todos los códigos relevantes:

parameter C_S1_INPUT_LENGTH      = 32,
parameter C_NUM_CYCLES_BITS      = 5

...

reg [C_NUM_CYCLES_BITS-1:0]        counter;
reg [C_NUM_CYCLES_BITS-1:0]        counter_z [3:0];  
reg [C_NUM_STATES-1:0]             current_state;
reg [C_S1_INPUT_LENGTH-1:0]        S1_input;
reg                                S1_input_val;   

...
  // Latch in inputs
  always@(posedge clk) begin        
      if(rst) begin
        current_state      <= S_IDLE;
        counter            <= 0;
        input_vector_i     <= 0;
        S2_input_val       <= 0;
      end 
      else begin
        case (current_state)
          S_IDLE:
            begin
                counter       <= 0;
                S2_input_val  <= 0;
                if (input_vector_val == 1) 
                  begin
                    current_state <= S_STAGE_ONE;
                    input_vector_i <= input_vector;
                  end
                else
                  current_state <= S_IDLE;
            end
          S_STAGE_ONE: 
            begin
                S2_input_val <= 0;
                if (counter < C_NUM_CYCLES-1) begin
                  counter       <= counter + 1;
                end

                if (S1_valid == ones) 
                  begin
                    current_state <= S_STAGE_TWO;
                    S2_input_val  <= 1;
                  end
                else 
                  current_state <= S_STAGE_ONE;
            end
          S_STAGE_TWO:
            // not relevant
          default:
            $display("wrong state!");
        endcase; 
      end
  end // always@ (posedge clk)

  always@(posedge clk) begin        
      if(rst) begin
        S1_input_val <= 0;
        S1_input     <= 0;
      end 
      else begin
        if (current_state == S_STAGE_ONE) begin
            S1_input_val <= 1;
            S1_input     <= input_vector_i[(counter_z[0]+1)*(C_S1_INPUT_LENGTH)-1 -: C_S1_INPUT_LENGTH];
        end
        else begin
            S1_input     <= 0;
            S1_input_val <= 0;
        end
      end
  end 

 always@(posedge clk) begin
     counter_z[0] <= counter;
     counter_z[1] <= counter_z[0];
     counter_z[2] <= counter_z[1];
     counter_z[3] <= counter_z[2];
 end 
    
pregunta stanri

3 respuestas

6

Se necesitan muchos LUT para construir un mux grande. Por ejemplo, si tiene LUT de 6 entradas, puede hacer un mux 4: 1 en una LUT, pero se necesitan 11 LUT para hacer un mux de 32 bits 1 de 1 bit.

Su contador se está replicando (como counter_reg ) de modo que el fanout en cualquier bit dado no sea excesivo. (Aunque no estoy realmente seguro de dónde viene el 1024).

Dado que realmente no necesita acceso "aleatorio" a los subcampos de input_vector_i , solo acceso secuencial, ¿ha considerado utilizar un registro de desplazamiento en su lugar?

    
respondido por el Dave Tweed
0

Utilizo principalmente VHDL, pero creo que su problema puede estar en esta declaración:

S1_input <= input_vector_i[(counter_z[0]+1)*(C_S1_INPUT_LENGTH)-1 -: C_S1_INPUT_LENGTH];

Creo que debería reemplazarse con algo como esto:

S1_input <= input_vector_i[(counter_z[0]+1)*(C_S1_INPUT_LENGTH)-1 -: (counter_z[0])*(C_S1_INPUT_LENGTH)];

De lo contrario, el ancho del segmento aumentará de 32 bits a 1024 bits en función del valor de counter_z [0], lo que explicaría por qué la señal de counter_reg tiene un tamaño de 1024 bits.

    
respondido por el kjgregory
0

En esta línea S1_input <= input_vector_i[(counter_z[0]+1)*(C_S1_INPUT_LENGTH)-1 -: C_S1_INPUT_LENGTH]; donde se infiere el mux, la señal de selección del mux debe calcularse evaluando counter_z[0]+1 . El retraso de este cálculo se sumará con el tiempo que demora la muxing real, disminuyendo así la frecuencia máxima de operación. Si el resultado del cálculo ya estaba disponible "precomputado" en un registro, el tiempo podría mejorarse, ya que la señal de selección no tendría que generarse en el mismo ciclo de reloj en que se realiza la muxing.
Sin embargo, para este gran mux, este cambio solo producirá una mejora relativamente pequeña.

    
respondido por el damage

Lea otras preguntas en las etiquetas