Cuando trato de sintetizar el siguiente código Verilog usando Xilinx XST, aparece el error "Constante real no admitida". Si trato de envolver esa expresión en una función $rtoi, XST da un error diferente: "Llamada de función del sistema no admitida".
Usando las herramientas de síntesis de Xilinx, ¿es posible convertir una constante real en una constante entera? ¿Si es así, cómo?
module example(clk, n_rst, tick, done);
parameter CLOCK_HZ = 50_000_000;
parameter BAUD_RATE = 3_000_000;
input clk, n_rst;
output reg tick, done;
reg [31:0] counter;
always @(posedge clk, negedge n_rst) begin
if (!n_rst) begin
counter <= 32'h00000000;
tick <= 0;
done <= 0;
end
else if (counter == (0.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (1.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (2.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (3.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (4.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (5.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (6.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (7.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (8.5*CLOCK_HZ/BAUD_RATE) || // ERROR:Xst:850 - Unsupported real constant
counter == (9.5*CLOCK_HZ/BAUD_RATE)) // ERROR:Xst:850 - Unsupported real constant
begin
counter <= counter + 1;
tick <= 1;
done <= 0;
end
else if (counter == 10*CLOCK_HZ/BAUD_RATE) begin
counter <= 32'h00000000;
tick <= 0;
done <= 1;
end
else begin
counter <= counter + 1;
tick <= 0;
done <= 0;
end
end
endmodule
Dado que no hay otras respuestas próximas, sugeriré un enfoque alternativo.
En lugar de dos parámetros CLOCK_HZ y BAUD_RATE, utilice un solo parámetro DIVIDE_RATIO.
Luego, los valores para la comparación se pueden calcular como DIVIDE_RATIO[n:1], DIVIDE_RATIO, (3*DIVIDE_RATIO)[n:1], etc. y nunca se crea ningún valor de coma flotante.
La desventaja de esto en relación con lo que tiene es que si la relación de división no es un número entero exacto, su enfoque suavizaría los errores en la tasa de ticks durante 10 ciclos, mientras que el mío tendría un poco más de error en la tasa de ticks en comparación con la relación de división "ideal".
Además, aunque no es lo que preguntaste, te sugiero que busques formas alternativas de organizar tu mostrador por completo. Tal como está su código, está utilizando un registro de 32 bits para mantener (y haciendo comparaciones de 32 bits) un contador que nunca contará por encima de 600, suponiendo que los valores predeterminados que utilizó para los parámetros no sean anulados por la persona que llama. Creo que podría obtener todos los mismos estados con 9 o 10 bits de estado.
Editar - un enfoque alternativo:
Otra forma de hacerlo que resuelve tanto el problema del punto flotante como el problema de la precisión es usar un contador de saltos. (código a mano alzada, no probado):
parameter jump = xxx; /// jump = 2^32 * BAUD_RATE / CLOCK_HZ
reg [32:0] ctr;
always @ (posedge clk) begin
ctr <= ctr[31:0] + jump;
tick <= ctr[32];
end
Al permitir que el contador simplemente se dé la vuelta en lugar de restablecerse a 0 después del conteo de la terminal, obtiene una tasa de tic que promedia correctamente hasta los límites de las matemáticas enteras de 32 bits, pero no tiene ningún punto flotante para confundir el Verilog compilador o sintetizador.
Deberá agregar la lógica de reinicio y un segundo contador para contar los ticks y generar la señal de "hecho". Para obtener exactamente lo que tenía antes, también necesitará
wire real_tick;
assign real_tick = tick & ~done;
Si la salida de tick tiene que estar libre de fallas, tendría que hacerlo en lógica secuencial.
La herramienta está tratando de decirte, cortésmente: "Oye, amigo, no soy un compilador de C". :)
Además de elegir una representación de punto fijo adecuada para los números con los que está trabajando, no debe sintetizar contadores en términos de adiciones y comparaciones con un recuento terminal. En su lugar, inicie el contador en el valor terminal y pruébelo contra cero. Esto ahorrará un sumador y acortará la ruta lógica.
dlitz