sábado, 2 de julio de 2011

Como mantener (1) el nombre de una señal y (2) un/varios registro/s después de la Síntesis

A veces nos encontramos con la sorpresa que la restricción (constraint) que aplicamos a una señal en particular nos genera un error que mas o menos nos dice que la señal que se quiere restringir no existe (!)(?).... entonces nos preguntamos: pero si la señal está en el código, como puedo obtener este mensaje de error diciendo que la señal no existe? . . .  
Pues, sucede que la herramienta de síntesis muchas veces absorbe algunas señales durante el proceso de optimización y síntesis. Esto sucede porque cuando una señal pasa de un bloque lógico a otro lo que la herramienta de síntesis hace es asignarle un nombre a veces aleatorio, a veces una combinación de los nombres de las señales. Así, cualquier restricción escrita sobre la señal original no será posible que se aplique, como así también si se desea encontrar esa señal dentro de una herramienta de depuración, no será posible, pues el nombre original, que es el que estamos usando en las restricciones o en la herramienta de depuración (debug) interna del FPGA (Chipscope(Xilinx) /SignalTap(Altera)/ Reveal(Lattice)), no existe más.
Para lograr que la señal que deseamos sea mantenida, y por ende mantenga su nombre, se debe usar un atributo de síntesis que normalmente se llama 'keep' (mantener). El uso del atributo 'keep' sobre una señal le dice a la herramienta de síntesis que mantenga la señal, previniendo que la señal con la cual se asocia el atributo sea absorbida y por ende cambiada de nombre. Como 'keep' es un atributo se síntesis el nombre del atributo en sí cambia dependiendo de la herramienta de síntesis que se use:

- XST Xilinx: atributo es 'keep' y es definido como 'string'
- Quartus Altera: atributo es 'keep' y es definido como 'boolean'
- Synplify (para clq vendedor): atributo es 'syn_keep' y es definido como 'boolean'
- Precision (para clq vendedor): atributo es 'keep'

Como todo atributo, 'keep' debe primero ser definido y luego se lo asocia a la señal que se desea mantener (keep). Ejemplo:


1 -- declaracion de la senal interna
2 signal dato_interno: std_logic;
3
4 -- declaracion del attributo
5 attribute keep: string;
6 -- asociacion del atributo con una senal especifica
7 attribute keep of dato_interno: signal is "true";


En el ejemplo al especificar el atributo de síntesis 'keep' como 'true' se está asociando el atributo 'keep' a la señal dato_interno . De este modo el nombre 'dato_interno' asociado a esa señal será mantenido, y por ello será posible referirlo ya sea en el archivo de restricción o en la herramienta de depuración (debug) interna del FPGA.
El mismo ejemplo para los casos en que 'keep' es definido como boolean es el siguiente: 


1 -- declaracion de la senal interna
2 signal dato_interno: std_logic;
3
4 -- declaracion del attributo
5 attribute syn_keep: boolean;
6 -- asociacion del atributo con una senal especifica
7 attribute syn_keep of dato_interno: signal is true;

Como resúmen se puede decir que en las siguientes circunstancias este atributo 'keep' es útil: 
- Para preservar una señal (cable) que de otro modo seria removida como resultado de la optimización, o renombrada en caso de ser absorbida en un bloque lógico. 
- Para prevenir que celdas duplicadas sean unidas durante optimización. En estos casos 'keep' debería ser asociado con las entradas a las celdas que se desean preservar. 
Un ejemplo de este último caso es el siguiente: 


 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3
 4 entity test_keep is
 5   port(
 6     dato_a: in  std_logic;
 7     dato_b: in  std_logic;
 8     clk   : in  std_logic;
 9     out_1 : out std_logic;
10     out_2 : out std_logic
11     );
12 end entity test_keep;
13
14 architecture beh of test_keep is
15  signal and_interna: std_logic;
16  signal and_out_ff1: std_logic;
17  signal and_out_ff2: std_logic;
18
19  attribute syn_keep: boolean;
20  attribute syn_keep of and_out_ff1: signal is true;
21  attribute syn_keep of and_out_ff2: signal is true;
22
23 begin
24
25  and_interna <= dato_a and dato_b;
26  and_out_ff1 <= and_interna;
27  and_out_ff2 <= and_interna;
28
29  test: process (clk)
30  begin
31   if(rising_edge(clk)) then
32     out_1 <= and_out_ff1;
33     out_2 <= and_out_ff2;
34   end if;
35  end process test;
36 end beh;
 



Los resultados de la implementación del código del ejemplo se pueden ver debajo. En la parte izquierda la implementación sin el uso del atributo keep, y sobre la derecha se muestra la conservación de los registros, tal como es descrito en el código, como resultado del uso del atributo 'keep'.





Finalmente, para completar en detalle este tema, quiero comentarles que existe otro atributo similar (pero no igual) comúnmente llamado 'preserve' o 'syn_preserve'. Este atributo se usa para preservar registros, NO se usa para preservar señales (cables). 
El ejemplo anterior puede ser re-escrito para preservar los registros utilizando 'syn_preserve' sobre los dos registros. Debajo se puede encontrar el código correspondiente: 


 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3
 4 entity test_keep is
 5   port(
 6     dato_a: in  std_logic;
 7     dato_b: in  std_logic;
 8     clk   : in  std_logic;
 9     out_1 : out std_logic;
10     out_2 : out std_logic
11     );
12     attribute syn_preserve: boolean;
13     attribute syn_preserve of out_1: signal is true;
14     attribute syn_preserve of out_2: signal is true;
15 end entity test_keep;
16
17 architecture beh of test_keep is
18  signal and_interna: std_logic;
19
20 begin
21
22  and_interna <= dato_a and dato_b;
23
24  test: process (clk)
25  begin
26   if(rising_edge(clk)) then
27     out_1 <= and_interna;
28     out_2 <= and_interna;
29   end if;
30  end process test;
31 end beh;


Las implementaciones respectivas se observan a continuación: 






Cabe mencionar que en éste ejemplo se hace uso del atributo 'syn_preserve' para mantener un registro de un puerto de salida del componente declarado en la entidad. Por esta razón el atributo se define y asocia a la señal (puerto) donde está declarada, es decir en la entidad. Sin embargo, se debe tener claro, que este atributo se puede asociar también a registros internos del componente. En este caso, el atributo se definiría y asociaría en la parte declarativa de la arquitectura, que es donde está declarada la señal de salida del registro. 


Nota: dependiendo de la fuente consultada, algunos consideran 'keep' como una Directiva, otros como un Atributo. Por ejemplo en el manual de referencia de Synplify 'syn_keep' es considerado una Directiva, mientras que en los manuales del XST y Quartus es considerado un Atributo. Independientemente de como es considerado, la función del atributo 'keep' es exactamente la misma. 

No hay comentarios:

Publicar un comentario