¿Por qué este Verilog acapara 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 esto:

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 eso rlevery lleverson de un bit de ancho, y necesito que tengan tres bits de ancho. Tonto de mí. Cambié el código para ser:

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

entonces había suficientes pedazos. 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 porque, cuando creo que empiezo a entender a Verilog y al CPLD, sucede algo que muestra que claramente no entiendo.

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 .

EDITAR 2: según 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 aún consume enormes recursos.

EDITAR 3 -

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

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 sucedió. Hice muchos cambios para implementar nuevos algoritmos. Un factor que contribuyó fue una 'ROM' de 111 elementos de 15 bits. Esto consumió un número modesto de macrocélulas pero muchode términos del producto: casi todos los disponibles en el xc2c64a. Busqué 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. Supuse 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 los recursos y me indujo a esperar cierta línea de base. 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 atribuí esto al primero exclusivamente.

Después de todo esto, era bueno en macrocélulas pero había agotado los términos de mi producto. La mitad de la ROM era un lujo, en realidad, ya que solo eran las 2 comp 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 producto.

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

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

Tony Ennis
fuente
¿no todos los signos de interrogación implican efectivamente un multiplexor, y estructuralmente también los has conectado en cascada? ¿Cuántas macroceldas esperabas que tomara?
vicatcu
No sé cuántas macrocélulas debería consumir la construcción. Sin embargo, teniendo en cuenta que mi proyecto actualmente está consumiendo 34 macrocélulas, incluidos esos dos multiplexores '1 bit', y que estos son una pequeña parte del proyecto, me sorprende este resultado.
Tony Ennis
¿Qué herramienta estás usando?
El Photon
ISE de Xilinx ...
Tony Ennis
En el código en su edición, creo que quiere en |lugar de ||.
El Photon

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 configurada más a la izquierda si se configura más de una.

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

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

Sin embargo, la Guía del usuario XST de Xilinx (pág. 80) define un codificador de prioridad más cercano a lo que codificó. Las entradas están numeradas desde 0, por lo que cuando se establece lsb de la entrada, se obtiene una salida 0. Sin embargo, la definición de Xilinx no proporciona especificaciones para la salida cuando todos los bits de entrada son claros (su código generará 3'7).

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

Aquí está la forma recomendada de Xilinx para un codificador de prioridad 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 = 3b000;
    else if (sel[1]) code = 3b001;
    else if (sel[2]) code = 3b010;
    else if (sel[3]) code = 3b011;
    else if (sel[4]) code = 3b100;
    else if (sel[5]) code = 3b101;
    else if (sel[6]) code = 3b110;
    else if (sel[7]) code = 3b111;
    else code = 3bxxx;
end
endmodule

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

Creo que puede obtener esto instanciando el módulo codificador Xilinx con

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

No he reunido todos los bits 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 lleverlógica, probablemente pueda reducir el uso de recursos haciendo un módulo codificador modificado, siguiendo la plantilla Xilinx, pero requiriendo solo 7 bits de entrada (sus 6 bits LLmás un bit adicional que sube cuando los otros 6 están bajos).

El uso de esta plantilla supone que la versión de ISE que tiene está usando 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é en realidad corresponde a su versión de ISE. De lo contrario, verifique el estilo recomendado en su documentación para ver qué espera su herramienta.

El fotón
fuente
Gracias, eso tomará algún tiempo para digerir. Mi ISE está usando XST aunque no sé qué versión.
Tony Ennis
La clave es tener (* priority_extract="force" *)y, probablemente, también incluir explícitamente el resultado de no importar aunque cubra todas las entradas posibles. (Sin ella, XST probablemente esté tratando de generar una tabla de búsqueda completa, por eso hay tantos términos de productos) Intente agregar primero la opción no importa. Si no funciona, intente usar la placa de cocción Xilinx exactamente.
El Photon
Implementé una copia completa del código anterior y no obtuve un resultado mejorado. Las páginas de resumen ISE indican que se reconoció un MUX, aunque el reconocimiento no fue tan fuerte como para otras construcciones. Publicaré la información relevante en unos minutos.
Tony Ennis
editar - ignore el comentario anterior sobre 'reconocimiento fuerte' - está ahí, me lo perdí anoche; Rehice el trabajo y la realidad funciona correctamente.
Tony Ennis
6

La respuesta de ThePhoton es excelente. Me gustaría agregar información adicional aquí para su consideración. Esto se debe al hecho de que, a pesar de que tenemos dispositivos FPGA y CPLD de última generación que utilizan HDL y herramientas de síntesis, puede ser informativo observar de cerca las cosas diseñadas hace años. Quédate conmigo mientras paso por esto para 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 la cantidad de transistores al mínimo. Puede buscar en la web partes lógicas con números de parte genéricos como 74HC148 o MC14532B para encontrar hojas de datos que incluyen diagramas lógicos equivalentes para estas partes. El siguiente diagrama es un ejemplo tomado de la hoja de datos de TI para la parte 74HC148 .

ingrese la descripción de la imagen aquí

Esta lógica implementa la siguiente tabla de verdad (tomada de la misma hoja de datos):

ingrese la descripción de la imagen aquí

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

ingrese la descripción de la imagen aquí

La misma hoja de datos muestra las ecuaciones lógicas para el MC14532B de la siguiente manera:

ingrese la descripción de la imagen aquí

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

Michael Karas
fuente
Gracias, lo haré. Este problema me está matando. Creo que anteriormente se sintetizaba de manera más eficiente. Y luego cambié algo. / selfbonk
Tony Ennis
Gracias, lo he implementado. No hizo una diferencia material, desafortunadamente.
Tony Ennis
Buena respuesta. Veamos a Tony cuántos términos de producto debería necesitar para implementar esta lógica. Tony, si usas las repeticiones de Xilinx o las ecuaciones de Michael, y aún estás generando cientos de términos de productos, entonces debes buscar un cambio sutil en algún otro lugar de tu código que pueda haber causado el problema; o bien, mire con mucho cuidado el archivo de registro de síntesis para ver si sucede algo que no espera.
El Photon
Estoy completamente de acuerdo con @ThePhoton. He manchado algo. Estoy tan seguro como puedo estar de que esto solía funcionar, ni siquiera noté el consumo que era tan pequeño. Oh, bueno, es una buena excusa para comenzar a comprender más la información del Resumen.
Tony Ennis