¿Por qué este Verilog absorbe 30 macrocélulas y cientos de términos de productos?

8

Tengo un proyecto que consume 34 de las macrocélulas de un Xilinx Coolrunner II. Noté que tenía un error y lo rastreé hasta aquí:

assign rlever = RL[0] ? 3'b000 :
                RL[1] ? 3'b001 :
                RL[2] ? 3'b010 :
                RL[3] ? 3'b011 :
                RL[4] ? 3'b100 :
                RL[5] ? 3'b101 :
                RL[6] ? 3'b110 :
                        3'b111;

assign llever = LL[0] ? 3'b000 :
                LL[1] ? 3'b001 :
                LL[2] ? 3'b010 :
                LL[3] ? 3'b011 :
                LL[4] ? 3'b100 :
                LL[5] ? 3'b101 :
                        3'b110 ;

El error es que rlever y llever tienen un bit de ancho, y necesito que tengan un ancho de tres bits. Tonto de mí. He cambiado el código para ser:

wire [2:0] rlever ...
wire [2:0] llever ...

así que había suficientes bits. Sin embargo, cuando reconstruí el proyecto, este cambio me costó más de 30 macrocélulas y cientos de términos de productos. ¿Alguien puede explicar lo que he hecho mal?

(La buena noticia es que ahora simula correctamente ... :-P)

EDITAR -

Supongo que estoy frustrado por el momento en que creo que empiezo a entender a Verilog y al CPLD, sucede algo que demuestra que claramente no entiendo no .

assign outp[0] = inp[0] | inp[2] | inp[4] | inp[6];
assign outp[1] = inp[1] | inp[2] | inp[5] | inp[6];
assign outp[2] = inp[3] | inp[4] | inp[5] | inp[6];

La lógica para implementar esas tres líneas ocurre dos veces. Eso significa que cada una de las 6 líneas de Verilog consume aproximadamente 6 macrocélulas y 32 términos de producto cada una .

EDIT 2 - De acuerdo con la sugerencia de @ ThePhoton sobre el cambio de optimización, aquí hay información de las páginas de resumen producidas por ISE:

Synthesizing Unit <mux1>.
    Related source file is "mux1.v".
    Found 3-bit 1-of-9 priority encoder for signal <code>.
Unit <mux1> synthesized.
(snip!)
# Priority Encoders                                    : 2
 3-bit 1-of-9 priority encoder                         : 2

Claramente el código fue reconocido como algo especial. Sin embargo, el diseño sigue consumiendo recursos tremendos.

EDIT 3 -

Hice un nuevo esquema que incluye solo el mux que recomendó @thePhoton. La síntesis produjo un uso insignificante de los recursos. También sinteticé el módulo recomendado por @Michael Karas. Esto también produjo un uso insignificante. Así que algo de cordura está prevaleciendo.

Claramente, mi uso de los valores de la palanca está causando consternación. Más por venir.

Edición final

El diseño ya no es una locura. Sin embargo, no estoy seguro de lo que pasó. Hice muchos cambios para implementar nuevos algoritmos. Un factor contribuyente fue una 'ROM' de 111 elementos de 15 bits. Esto consumió una cantidad modesta de macrocélulas pero un lote de términos de productos, casi todos los disponibles en el xc2c64a. Busco esto pero no lo había notado. Creo que mi error estaba oculto por la optimización. Las "palancas" de las que estoy hablando se utilizan para seleccionar valores de la ROM. Supongo que cuando implementé el codificador de prioridad de 1 bit (roto), ISE optimizó parte de la ROM. Eso sería un buen truco, pero es la única explicación que se me ocurre. Esta optimización redujo notablemente el uso de recursos y me hizo esperar un cierto nivel de referencia. Cuando arreglé el codificador de prioridad (según este hilo), vi la sobrecarga del codificador de prioridad y la ROM que previamente se había optimizado y se lo atribuí exclusivamente al primero.

Después de todo esto, era bueno en macrocélulas pero había agotado los términos de mis productos. La mitad de la ROM era un lujo, en realidad, ya que era solo la composición de los 2 de la primera mitad. Eliminé los valores negativos, reemplazándolos en otro lugar con un cálculo simple. Esto me permitió intercambiar macrocélulas por términos de productos.

Por ahora, esto encaja en el xc2c64a; He usado el 81% y el 84% de mis términos de macrocélulas y productos, respectivamente. Por supuesto, ahora tengo que probarlo para asegurarme de que hace lo que quiero ...

Gracias a ThePhoton y Michael Karas por la asistencia. Además del apoyo moral que prestaron para ayudarme a resolver esto, aprendí del documento de Xilinx que publicó ThePhoton, e implementé el codificador de prioridad sugerido por Michael.

    
pregunta Tony Ennis

2 respuestas

7

El código que muestra es esencialmente un codificador de prioridad. Es decir, tiene una entrada de muchas señales, y su salida indica cuál de esas señales está configurada, dando prioridad a la señal que se encuentra más a la izquierda si se establece más de una.

Sin embargo, veo definiciones conflictivas del comportamiento estándar para este circuito en los dos lugares que revisé.

Según Wikipedia , el codificador de prioridad estándar numera sus entradas de 1. Es decir, si es el bit de entrada menos significativo está configurado, genera 1, no 0. El codificador de prioridad de Wikipedia emite 0 cuando no se establece ninguno de los bits de entrada.

Guía del usuario de XST de Xilinx (p. 80), sin embargo, define una prioridad Codificador más cercano a lo que codificaste. Las entradas están numeradas desde 0, por lo que cuando se establece el lsb de la entrada, se obtiene una salida de 0. Sin embargo, la definición de Xilinx no da ninguna especificación para la salida cuando todos los bits de entrada están libres (su código dará salida 3'd7).

La guía del usuario de Xilinx, por supuesto, determinará qué espera el software de síntesis de Xilinx. El punto principal es que se requiere una directiva especial (*priority_extract ="force"*) para que XST reconozca esta estructura y genere resultados de síntesis óptimos.

Esta es la forma recomendada de Xilinx para un codificador de prioridad de 8 a 3:

(* priority_extract="force" *)
module v_priority_encoder_1 (sel, code);
input [7:0] sel;
output [2:0] code;
reg [2:0] code;
always @(sel)
begin
    if (sel[0]) code = 3’b000;
    else if (sel[1]) code = 3’b001;
    else if (sel[2]) code = 3’b010;
    else if (sel[3]) code = 3’b011;
    else if (sel[4]) code = 3’b100;
    else if (sel[5]) code = 3’b101;
    else if (sel[6]) code = 3’b110;
    else if (sel[7]) code = 3’b111;
    else code = 3’bxxx;
end
endmodule

Si puede reorganizar su lógica circundante para permitirle usar el estilo de codificación recomendado de Xilinx, esa es probablemente la mejor manera de obtener un mejor resultado.

Creo que puedes obtener esto al crear una instancia del módulo del codificador Xilinx con

v_priority_encoder_1 pe_inst (.sel({~|{RL[6:0]}, RL[6:0]}), .code(rlever));

No he unido todos los bits de RL[6:0] para obtener un octavo bit de entrada que activará la salida 3'b111 cuando todos los bits RL estén bajos.

Para la lógica llever , probablemente pueda reducir el uso de recursos haciendo un módulo de codificador modificado, siguiendo la plantilla de Xilinx, pero requiriendo solo 7 bits de entrada (sus 6 bits de LL más un bit adicional que sube) cuando los otros 6 son todos bajos).

El uso de esta plantilla supone que la versión de ISE que está utilizando está utilizando el motor de síntesis XST. Parece que cambian las herramientas de síntesis en cada revolución importante de ISE, así que verifique que el documento que vinculé corresponda en realidad a su versión de ISE. De lo contrario, verifique el estilo recomendado en su documentación para ver qué espera su herramienta.

    
respondido por el The Photon
6

La respuesta de ThePhoton es excelente. Me gustaría agregar alguna información adicional aquí para su consideración. Esto se debe al hecho de que a pesar de que contamos con dispositivos FPGA y CPLD sofisticados con tecnología de punta que utilizan HDL y herramientas de síntesis, puede ser informativo mirar de cerca las cosas diseñadas hace años. Quédate conmigo mientras paso por esto hasta mi recomendación al final.

Hay partes lógicas discretas que realizan la función de codificación de prioridad. La lógica implementada por estas partes ha existido durante mucho tiempo cuando era esencial reducir el número de transistores al mínimo. Puede buscar en la web piezas lógicas con números de pieza genéricos como 74HC148 o MC14532B para encontrar hojas de datos que incluyan diagramas lógicos equivalentes para estas partes. El diagrama a continuación es un ejemplo tomado de la hoja de datos de TI para la parte 74HC148 .

Estalógicaimplementalasiguientetabladeverdad(tomadadelamismahojadedatos):

Tenga en cuenta que la familia de piezas anterior utiliza señales de entrada activas bajas. Otra hoja de datos para la ON Semiconductor MC14532B part muestra una tabla de verdad para la función de codificador utilizando la alta activa Señales de entrada similares a su ejemplo de Verilog.

LamismahojadedatosmuestralasecuacioneslógicasparaelMC14532Bdelasiguientemanera:

Es posible que desee considerar la posibilidad de codificar ecuaciones similares directamente en su código de Verilog para ver cómo se compara con su ejemplo actual. Es muy probable que resulte en un resultado mucho más favorable.

    
respondido por el Michael Karas

Lea otras preguntas en las etiquetas