Compresión de bits en Verilog

Estoy tratando de escribir un código Verilog para un multiplicador basado en el principio del ábaco. Quiero comprimir una matriz de 8X15 bits en las filas más bajas. Por ejemplo, para una matriz de

    p0 = 0000000000000000
    p1 = 1111111111111111
    p2 = 0000000000000000
    p3 = 1111111111111111
    p4 = 0000000000000000
    p5 = 1111111111111111
    p6 = 0000000000000000
    p7 = 1111111111111111

Quiero que mi salida sea:

    pp[0] = 000000000000000
    pp[1] = 000000000000000
    pp[2] = 000000000000000
    pp[3] = 000000000000000
    pp[4] = 111111111111111
    pp[5] = 111111111111111
    pp[6] = 111111111111111
    pp[7] = 111111111111111

He escrito el siguiente código para lograr esto:

    always @ (p0 or p1 or p2 or p3 or p4 or p5 or p6 or p7)
 begin
 pp[1] = p0;
 pp[2] = p1;
 pp[3] = p2;
 pp[4] = p3;
 pp[5] = p4;
 pp[6] = p5;
 pp[7] = p6;
 pp[8] = p7;

for (i=1; i<=15; i=i+1)
 begin
    for (j=8; j>=1; j=j-1)
    begin
       for (k=j-1; k>=1; k=k-1)
          begin
          if ((!pp[j][i]) && (pp[k][i]))
            begin
            pp[j][i] <= pp[k][i];
            pp[k][i] <= pp[j][i];
            end
          end
      end
  end
end

pero el resultado que obtengo es este:

    pp[0] = 000000000000000
    pp[1] = 000000000000000
    pp[2] = 111111111111111
    pp[3] = 000000000000000
    pp[4] = 111111111111111
    pp[5] = 000000000000000
    pp[6] = 111111111111111
    pp[7] = 111111111111111

¿Alguien puede decir dónde está la falla?

Respuestas (2)

Puede hacer que esto funcione si reemplaza las asignaciones que no bloquean con asignaciones de bloqueo. Todavía no es fácilmente sintetizable, pero estaría bien como banco de pruebas. Ejemplo a continuación.

Las asignaciones sin bloqueo que se usan <=no tienen efecto de inmediato, sino que se retrasan hasta un momento posterior, que se puede considerar como el final del paso de tiempo actual. Dado que todos los bucles for están dentro del mismo paso de tiempo, si utilizan asignaciones sin bloqueo, programan una serie de eventos para que ocurran al final del paso de tiempo actual. Entonces, los bucles for jy for ksiempre ven los valores iniciales de la matriz. Como se expresa este algoritmo, es necesario que estos dos bucles estén trabajando con los datos después de que se haya producido el intercambio.

module compressMe();

  reg [15:0] p0;
  reg [15:0] p1;
  reg [15:0] p2;
  reg [15:0] p3;
  reg [15:0] p4;
  reg [15:0] p5;
  reg [15:0] p6;
  reg [15:0] p7;

  reg [15:0] pp [7:0];

  integer i,j,k;

  reg swapTemp;

  initial
    begin
      p0 <= 16'b0000000000000000;
      p1 <= 16'b1111111111111111;
      p2 <= 16'b0000000000000000;
      p3 <= 16'b1111111111111111;
      p4 <= 16'b0000000000000000;
      p5 <= 16'b1111111111111111;
      p6 <= 16'b0000000000000000;
      p7 <= 16'b1111111111111111;
  end

  always @ (p0 or p1 or p2 or p3 or p4 or p5 or p6 or p7)
    begin
    pp[0] = p0;
    pp[1] = p1;
    pp[2] = p2;
    pp[3] = p3;
    pp[4] = p4;
    pp[5] = p5;
    pp[6] = p6;
    pp[7] = p7;

    for (i=0; i<=15; i=i+1)
      begin
          for (j=7; j>=1; j=j-1)
          begin
            for (k=j-1; k>=1; k=k-1)c
                beginc
                if (    ( !pp[j][i] )     &&    (  pp[k][i]  )    )   
                  begin
                  swapTemp = pp[j][i];
                  pp[j][i] = pp[k][i];
                  pp[k][i] = swapTemp;
                  end
                end
            end
        end
  end


  initial
    begin
    #100 for (i=0; i<=7; i=i+1)
        $display("pp[%d] = %16b ", i, pp[i]);
    end


endmodule

Esto producirá:

 ncsim> run
 pp[          0] = 0000000000000000 
 pp[          1] = 0000000000000000 
 pp[          2] = 0000000000000000 
 pp[          3] = 0000000000000000 
 pp[          4] = 1111111111111111 
 pp[          5] = 1111111111111111 
 pp[          6] = 1111111111111111 
 pp[          7] = 1111111111111111 

El problema es que está escribiendo código que sería apropiado para un lenguaje de programación de software en un lenguaje de descripción de hardware.

Recuerde, en un HDL, un forbucle describe construcciones de hardware paralelas, no pasos de procesamiento secuenciales.

En su caso, el forciclo externo es apropiado, ya que desea crear una lógica que maneje cada columna de forma independiente. Pero dentro de cada columna, desea contar la cantidad de unos y luego generar un vector de bits que tenga esa cantidad de bits establecidos en una fila. La forma más fácil de especificar esto podría ser simplemente enumerar todas las posibilidades con una casedeclaración o una tabla de búsqueda.

Si realmente quieres hacerlo con lógica, esta respuesta puede ofrecerte una pista. (Básicamente, está ordenando una lista de valores de 1 bit).