Tienes razón al adivinar el bucle for.
La lógica de bucle for es enorme cuando, después de que se desenrolla, la estática. Con su código actual, no puede manejar el peor de los casos donde n = 1023. Para cubrir esto con su código actual, necesitaría un bucle for con 1024 iteraciones.
En lugar de un contador hacia arriba, puede usar un contador hacia abajo y solo examinar una porción de la matriz, donde el índice representa lsb de la porción de la matriz. Por ejemplo:
for (i=9; i>=0; i=i-1) begin // lsb index of the slice
if (out[i+:11] >= cnt) begin // 11-bit slice compare
out[i+:11] = out[i+:11] - cnt; // 11-bit slice subtraction
avg[i] = 1'b1; // 1-bit assign
end
end
Esto para el bucle se desenreda a 10 iteraciones (9 a 0), cada iteración solo se ve en un segmento de 11 bits de out
y solo un bit de avg
. Es posible que no esté familiarizado con el operador +:
. Es un operador de división de bits introducido en IEEE Std 1364-2001. Lado izquierdo si el índice de inicio (dinámico está permitido) y el lado derecho es el bit con desplazamiento (debe ser una constante estática). Puede leer más sobre esto aquí .
Como se trata de una cuenta atrás, podemos asumir de forma segura (comprobado matemáticamente) que los bits superiores de la división son ceros y nunca tendremos subdesbordamiento con la condición de protección si. Así que ahora tenemos diez restadores de 11 bits, cada uno con asignadores de 1 bit, que es una lógica mucho más pequeña que los 642 (deberían ser 1024), restadores de 20 bits, cada uno con sumador de 10 bits.
Algunas otras sugerencias:
- Use el encabezado de estilo ANSI (compatible desde IEEE Std 1364-2001). Se trata de algunas líneas de código y, por lo tanto, menos propensas a errores tipográficos y copiar y pegar errores.
- Separe la lógica síncrona y la lógica de combinación. Esto significa declarar más firmas, pero generar le da un mejor control sobre qué es un flop y qué es la lógica de peine. También sigue las mejores prácticas. Tu bucle for debería salir en la lógica de peine.
- Use asignaciones no bloqueantes (
<=
) en su bloque lógico síncrono. Esto sigue las mejores prácticas de codificación y evita las condiciones de carrera de flop a flop en la simulación.
-
out
se puede simplificar a un registro de 10 bits, asumiendo que hiciste las sugerencias 2 & 3. Esto se debe a que sabemos que los bits superiores siempre serán ceros, por lo que podemos guardar 10 flops.
prueba de concepto: con un sencillo banco de pruebas SystemVerilog aquí :
module averager( // ANSI style header
input clk, rst,
input [9:0] n,
output reg [19:0] sum,
output reg [9:0] cnt,
output reg [9:0] out, // was [19:0]
output reg [9:0] avg
);
reg [19:0] next_sum, next_out;
reg [9:0] next_cnt, next_avg;
integer i;
always @* begin
next_sum = sum + n;
next_out = next_sum;
next_cnt = cnt + 1'b1;
next_avg = 10'b0;
for (i=9; i>=0; i=i-1) begin // lsb index for slice
if (next_out[i+:11] >= next_cnt) begin // 11-bit slice compare
next_out[i+:11] = next_out[i+:11] - next_cnt; // 11-bit slice subtract
next_avg[i] = 1'b1; // 1-bit assign
end
end
end
always @(posedge clk) begin
if (rst == 1'b1) begin
sum <= 20'b0;
cnt <= 10'b0;
out <= 10'b0; // was 20'b0
avg <= 10'b0;
end
else begin
sum <= next_sum;
cnt <= next_cnt;
out <= next_out[9:0]; // only assign lsb
avg <= next_avg;
end
end
endmodule
Si aún experimenta problemas en el área o el rendimiento no es lo suficientemente bueno, entonces debe canalizar su diseño y / o ver si hay un módulo dedicado de divisor + resto definido en su hoja de datos de FPGA que pueda crear una instancia.