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?
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 j
y for k
siempre 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 for
bucle describe construcciones de hardware paralelas, no pasos de procesamiento secuenciales.
En su caso, el for
ciclo 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 case
declaració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).