XST Verilog - Convertir constantes reales a enteras

2

Cuando intento sintetizar el siguiente código de Verilog con Xilinx XST, aparece el error "Constante real no compatible". Si intento ajustar esa expresión en una función $ rtoi, XST genera un error diferente: "Llamada de función del sistema no compatible".

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
    
pregunta dlitz

2 respuestas

0

Como no hay otras respuestas, sugeriré un enfoque alternativo.

En lugar de los dos parámetros CLOCK_HZ y BAUD_RATE, solo use 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 punto 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 error un poco más en la tick tasa en comparación con el índice de división "ideal".

Además, aunque no es lo que pediste, sugeriría buscar formas alternativas de organizar tu contador todos juntos. Mientras se encuentra el código, está utilizando un registro de 32 bits para mantener (y hacer 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 fueron reemplazados 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 ir que resuelve tanto el problema de punto flotante como el problema de 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 desplace en lugar de restablecerse a 0 después del recuento del terminal, se obtiene una tasa de marca que promedia correctamente los límites de la matemática de enteros de 32 bits, pero no tiene ningún punto flotante para confundir el compilador o sintetizador Verilog.

Necesitará agregar la lógica de reinicio y un segundo contador para contar los ticks y generar la señal '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 debe estar libre de errores, deberías hacerlo en lógica secuencial.

    
respondido por el The Photon
0

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 de terminales. En su lugar, inicie el contador en el valor terminal y pruébelo contra cero. Esto guardará un sumador y acortará la ruta lógica.

    
respondido por el John Miles

Lea otras preguntas en las etiquetas