Síntesis de un diseño multiplicador

He escrito un código verilog para un multiplicador que da resultados correctos después de la simulación. Pero, el código generado tras la síntesis de dicho código no da resultados correctos. De hecho, no da resultados. El archivo de registro creado después de la síntesis dice que podría haber posibles errores de sincronización con mi diseño, aunque he intentado sincronizar todo en el borde positivo del reloj. Además, también genera una advertencia que dice:

La variable o señal se maneja en más de un proceso o bloque. Esto puede causar desajustes de simulación entre los diseños originales y sintetizados. [CDFG2G-622]: 'qq[1]' en el módulo 'ab_mac' en el archivo '/ugassignments/ma3ps139/cadence/abacus8_syn/abacus8_chk.v' en la línea 59, columna 22.

No sé cómo rectificar esto. Por favor ayuda. Aquí está el código:

      module ab_mac (result, a, b, clk, reset, zero);
      output [16:1] result;
      input [8:1] a, b;
      input [11:0] zero;
      reg [8:1] A, B;
      input clk, reset;
      wire [16:1] p0, p1, p2, p3, p4, p5, p6, p7;
      reg [9:0] qq [16:1];
      reg [9:0] rr [16:1];
      wire [9:0] q [16:1];
      wire [3:0] ones [16:1];
      genvar j, i,  k, m;
      reg [4:0] count;

      part_prod_gen1 ppg (p0, p1, p2, p3, p4, p5, p6, p7, a, b);

     //load the partial products
     generate
 for (j=1; j<=16; j=j+1)
 begin: loop1
  always @ (posedge clk)
  begin
  if (!reset)
  begin
    if (count == 5'b00000)
    begin
    qq[j][9] <= p7[j];
    qq[j][8] <= p6[j];
    qq[j][7] <= p5[j];
    qq[j][6] <= p4[j];
    qq[j][5] <= p3[j];
    qq[j][4] <= p2[j];
    qq[j][3] <= p1[j];
    qq[j][2] <= p0[j];
    qq[j][1] <= 1'b0;
    qq[j][0] <= 1'b0;
    end

  else if (count[0] == 1)
    begin
      qq[j] <= q[j];
    end

  else 
    begin
      case (ones[j])
      4'b0010 : 
      begin {qq[j][9], qq[j][8]} <= 2'b0;
          if (j<16) qq[j+1][9-ones[j+1]] <= 1'b1; end

      4'b0011 : 
      begin {qq[j][9], qq[j][8]} <= 2'b0;
          if (j<16) qq[j+1][9-ones[j+1]] <= 1'b1; end

      4'b0100 : 
      begin {qq[j][9], qq[j][8], qq[j][7],qq[j][6]} <= 4'b0;
          if (j<15) qq[j+2][8-ones[j+2]] <= 1'b1; end

      4'b0101 : 
      begin {qq[j][9], qq[j][8], qq[j][7],qq[j][6]} <= 4'b0;
          if (j<15) qq[j+2][8-ones[j+2]] <= 1'b1; end

      4'b0110 : 
      begin {qq[j][9], qq[j][8], qq[j][7],qq[j][6]} <= 4'b0;
          if (j<15) qq[j+2][8-ones[j+2]] <= 1'b1; end

      4'b0111 : 
      begin {qq[j][9], qq[j][8], qq[j][7],qq[j][6]} <= 4'b0;
          if (j<15) qq[j+2][8-ones[j+2]] <= 1'b1; end

      4'b1000 : 
      begin {qq[j][9],qq[j][8],qq[j][7],qq[j][6],qq[j][5],qq[j][4],qq[j][3],qq[j][2]} <= 8'b0; 
          if (j<14) qq[j+3][7-ones[j+3]] <= 1'b1; end
      endcase
    end
end
end
end
   endgenerate

    //compress the partial products
      generate
      for (i=1; i<=16; i=i+1)
      begin: loop2
      count_one con (ones[i], qq[i]);
      shift sft (q[i], qq[i]);
      end
      endgenerate

assign result[1] = qq[1][9] & (!reset) ,
       result[2] = qq[2][9] & (!reset) ,
       result[3] = qq[3][9] & (!reset) ,
       result[4] = qq[4][9] & (!reset) ,
       result[5] = qq[5][9] & (!reset) ,
       result[6] = qq[6][9] & (!reset) ,
       result[7] = qq[7][9] & (!reset) ,
       result[8] = qq[8][9] & (!reset) ,
       result[9] = qq[9][9] & (!reset) ,
       result[10] = qq[10][9] & (!reset) ,
       result[11] = qq[11][9] & (!reset) ,
       result[12] = qq[12][9] & (!reset) ,
       result[13] = qq[13][9] & (!reset) ,
       result[14] = qq[14][9] & (!reset) ,
       result[15] = qq[15][9] & (!reset) ,
       result[16] = qq[16][9] & (!reset) ;

      always @ (posedge clk)
      if (reset)
      count <= 5'b00000;
      else
      begin
      count <= count + 1'b1;
      if(count == 5'b10001)
     count <= 5'b00000;
     end  

     endmodule

Además, aquí están los códigos para las otras instancias en caso de que desee verificar:

    module shift (out, in);
    output[9:0] out;
    input [9:0] in;
    wire [3:0] ones;
    genvar i;
    count_one coon (ones, in);
    generate
    for (i=9; i>=0; i=i-1)
    begin: loop
    assign out[i] = (i > (9-ones)? 1 : 0);
    end
    endgenerate
    endmodule  

   module count_one (ones, column);
   output [3:0] ones;
   input [9:0] column;
   assign ones =    column[9]+column[8]+column[7]+column[6]+column[5]+column[4]+column[3]+column[2]+column[1]+column[0];
  endmodule

  module part_prod_gen (p0, p1, p2, p3, p4, p5, p6, p7, in1, in2);
  output [15:1] p0, p1, p2, p3, p4, p5, p6, p7;
  input [7:0] in1, in2;
  wire [7:0] pp [7:0];
  genvar i, j;

  generate
  for (i=0; i<=7; i=i+1)
  begin: loop1
   for (j=0; j<=7; j=j+1)
   begin: loop2
   assign pp[i][j] = in1[j] & in2[i];
 end
 end
 endgenerate

 assign p0 = {7'b0, pp[0][7], 7'b0};
 assign p1 = {6'b0, pp[1][7], pp[1][6], pp[0][6], 6'b0};
 assign p2 = {5'b0, pp[2][7:5],pp[1][5],pp[0][5],5'b0};
 assign p3 = {4'b0, pp[3][7:4],pp[2][4],pp[1][4],pp[0][4],4'b0};
 assign p4 = {3'b0, pp[4][7:3],pp[3][3],pp[2][3],pp[1][3],pp[0][3],3'b0};
 assign p5 = {2'b0, pp[5][7:2],pp[4][2],pp[3][2],pp[2][2],pp[1][2],pp[0][2],2'b0};
 assign p6 = {1'b0, pp[6][7:1],pp[5][1],pp[4][1],pp[3][1],pp[2][1],pp[1][1],pp[0]   [1],1'b0};
 assign p7 = {pp[7][7:0],pp[6][0],pp[5][0],pp[4][0],pp[3][0],pp[2][0],pp[1][0],pp[0][0]};
 endmodule
@Xcodo, he publicado las partes restantes del código. Por favor, mire esto.
Puede usar bucles for dentro de un proceso en Verilog (o VHDL), la sintaxis es la misma que en C. Sin embargo, solo se puede sintetizar si la condición del bucle es constante en el momento de la compilación, es decir, que la variable del bucle se incrementa hacia arriba o hacia abajo. a un valor fijo, ya sea una constante numérica o un parámetro de módulo. En hardware esto es equivalente a múltiples copias del circuito en paralelo (como genera). Solo tenga cuidado de asegurarse de que ninguna de las iteraciones dependa del resultado de otra iteración en el mismo ciclo de reloj o obtendrá una cadena de circuitos en lugar de un conjunto paralelo.

Respuestas (1)

Supongo que está sintetizando para un FPGA o CPLD. El simulador simulará con éxito muchas construcciones de lenguaje que son Verilog técnicamente válidas, pero que son muy difíciles de traducir a hardware de lógica programable real.

No puedo sintetizar su bloque yo mismo porque no tengo los módulos part_prod_gen1, count_one y shift disponibles, pero los problemas que puedo ver al leer el código son:

  • El uso de bloques posedge y negedge always@ para señales que no sean líneas de reloj y reinicio a menudo no es sintetizable (consulte esta respuesta ). Creo que usar registros de desplazamiento (explícitamente o con un registro signal_old) es un enfoque mucho más confiable que probar la posición de cuenta [0].
  • Matriz de registros q los elementos q se asignan en multiples procesados ​​separados (siempre bloques). Esto no se puede sintetizar ya que los bloques de proceso se ejecutan en paralelo y el flip-flop de registro no se puede configurar desde dos fuentes diferentes. Puede corregir esto combinando gran parte del código en un solo proceso secuencial (que es feo y más difícil de depurar) o usando cables intermedios que se combinan en un solo proceso. Ver esta respuesta para un problema similar.

    genvar j, i,  k, m;
    // ... other code
    //load the partial products
    generate
      for (j=1; j<=16; j=j+1)
      begin: loop1
        always @ (posedge clk)
        begin
          if (!reset) begin
          // ... qq assignments
          end
        end
      end
    endgenerate
    
    /* should be */
    
    genvar i,  k, m;
    integer j; // j as integer not genvar
    // ... other code
    //load the partial products
    //generate // comment out or remove
    always @ (posedge clk)
    begin
      for (j=1; j<=16; j=j+1) // <- for-loop inside always block
      begin: loop1
        if (!reset) begin
        // ... qq assignments
        end
      end
    end
    //endgenerate // comment out or remove
    
He modificado el diseño según los cambios que sugeriste. Todavía no da los resultados deseados.
¿Tiene alguna advertencia de síntesis ahora? Solo estoy echando un vistazo con los módulos adicionales, veré qué puedo hacer en los próximos 10 minutos...
sí, tengo las advertencias de síntesis como antes. Publicaré el código actualizado en breve.
He publicado el código actualizado. La advertencia se genera cuando qq[16:1][9] se asigna como resultado de qq[2][9] en adelante
He encontrado la fuente de eso. En la declaración de caso basada en unos[j], asigna valores a qq[j+1]. En el simulador o en papel, intente pasar por esa lógica para averiguar qué está asignando realmente cada vez. Asegúrese de que, para cualquier condición, cada bit qq[][] solo se asigne una vez por ciclo de reloj. Me temo que tengo que ir a trabajar, así que no podré volver a mirar hasta esta noche. ¡Déjame saber cómo te va!
¡Revisé la lógica en papel pero no encontré ninguna asignación conflictiva a qq[][] para ningún ciclo de reloj! Además, mi código está dando resultados correctos en la simulación antes de la síntesis, por lo que no puede haber un problema con la lógica. De todos modos, no está dando resultados correctos después de la síntesis, así que supongo que tengo que encontrar una forma alternativa.
Lo siento, me perdí que j todavía estaba en una declaración de generación (no me está yendo mal ya que no he usado Verilog en aproximadamente cinco años, ¡solo VHDL!) Mueva j a un bucle for DENTRO del bloque siempre y lo hará en menos sintetizar.
Para aclarar, la declaración de generación es solo una abreviatura conveniente para escribir el proceso always@ 16 veces. En cada uno de esos bloques existe la posibilidad (el sintetizador no es demasiado inteligente) de que el proceso pueda escribir en un registro qq dado, por lo que se proporciona como controlador. Todos estos procesos generados tienen derecho a impulsar la salida, que no es sintetizable.
@Xcodo, buena depuración. Agregué un ejemplo de código de la segunda viñeta para ser más específico.
Sí, gracias @Greg, ¡probablemente lo que debería haber hecho todo el tiempo!
Gracias por la explicación @Xcodo! Pero nuevamente surge el problema de que mover j a un bucle for dentro del bloque always hará que mi asignación a qq[][] sea secuencial en lugar de concurrente, ¿no es así? Quiero decir, ¿al hacer esto se actualizará toda la matriz qq[][] en un ciclo de reloj?
@titan, todo se hará en un ciclo de reloj. No hay elementos de retardo en el bloque siempre. El bucle for se ejecutará en tiempo cero.
¡Muchas gracias @Xcodo por tu ayuda! Mi código sintetizado.
Muy feliz de ayudar. ¡No dudes en etiquetarme de nuevo si todo sale mal!