Mostrando entradas con la etiqueta ISE. Mostrar todas las entradas
Mostrando entradas con la etiqueta ISE. Mostrar todas las entradas

viernes, 28 de septiembre de 2018

Quartus-ModelSim: Como 'ver' mejor las formas de ondas y facilitar el debug

En un blog anterior (link) describí la personalización de las formas de ondas visualizadas en ModelSim en el entorno ISE de Xilinx. Debido al pedido de muchos de Uds. les presento ahora lo mismo para para los usuarios de Quartus de Altera. Como ya leerán en la nota de aplicación que presento, cuando se invoca cualquier tipo de simulación desde el Quartus, ModelSim es automáticamente abierto, mostrando las formas de ondas resultantes del test bench en el panel llamado Wave View. Debido a la configuración de ModelSim (detallada en un archivo tipo script) que por defecto se invoca, solo las señales de la entidad de mayor jerarquía son mostradas, y ... nada más... Entonces, una vez abierta esta ventana Wave View si se desean ver señales internas del diseño bajo test, o cambiar la posición y/o color de las señales mostradas, o agregar divisores, y tantas otras características que ofrece ModelSim para hacer, es posible llevarlas a cabo, pero una vez cerrado ModelSim todas las modificaciones realizadas se pierden!. Así, cuando se corra la misma simulación de nuevo, se deberá empezar otra vez con las modificaciones. Les suena familiar el problema?????

En la 'Application Note' que les presento se detallan los pasos a seguir, para que cuando se invoque ModelSim desde Quartus, la simulación, y específicamente, el Wave View contenga toda la información que uno desea/necesita para una buena verificación y un fácil debug.

Aqui esta el link para bajar la 'Application Note', que por ahora está en Inglés, pero si hay unos cuantos pedidos, la pasaré al Español: 


Hasta la próxima ! 

miércoles, 17 de febrero de 2016

Como Filtrar los Warnings/Infos en el ISE .....

Introducción

Después de ejecutar algunos de los procesos disponibles en el entorno ISE, se generan diversos y numerosos mensajes. Estos mensajes permiten que el diseñador sepa de la "salud" del proyecto. En algunos casos, es posible que  se desee suprimir un mensaje en particular que aparezca en el "Errors and Warnings Report". Por ejemplo, luego de ejecutar un proceso del ISE, se puede obtener un mensaje de advertencia (Warning) alrededor de señales que deberían estar conectadas a ciertos pines y que no lo están. ISE permite suprimir, en realidad filtrar, un mensaje en particular (o varios mensajes). La herramienta se puede utilizar para este propósito es llamada "Message Filters" ("Filtros de mensajes").

Mensaje que se puede filtrar


No todos los mensajes generados por los diversos procesos del ISE pueden ser filtrados. Primeramente, los mensajes que se pueden filtrar son los mensajes tipo "Warning" ("Advertencia") o mensajes tipo "INFO" ("Información") y son seguidos por un nombre de biblioteca y el número de mensaje. 
Por ejemplo, el siguiente mensaje se puede filtrar:


   
En este mensaje de advertencia, Xst es el nombre de la biblioteca, y 2677 es el número del mensaje de advertencia.
Nota: Los mensajes de Error no se pueden filtrar. Del mismo modo, los mensajes de algunos procesos no se pueden filtrar (por ejemplo, los mensajes generados por el software de terceros, tales como el software de Synopsys). De todos modos, si se intenta filtrar un mensaje que no se puede filtrar, aparecerá una ventana que indica que el mensaje no se puede filtrar.

Procedimientos Para Filtrar Mensajes

1- Una vez que tenga el proyecto abierto en ISE, habilitar el filtrado de mensajes de la siguiente manera:
    • Abra el panel Design Summary haciendo Project->Design Summary/Reports.
    • En el panel superior de Design Summary, en Design Overview seleccione Summary
    • En el panel inferior de Design Summary, seleccione Enable Message Filtering.

    • Nota: también es posible habilitar el filtrado de mensajes en las opciones de propiedades disponibles en el proyecto: Project-> Design Properties,  en el panel inferior llamado Project Settings.

2- En el panel Processes del Project Navigator del ISE, ejecute el proceso que genera los mensajes que se desean filtrar.
Por ejemplo , ejecutar el proceso Synthesize-XST.

3- En el panel Design Summary, y en las opciones de Errors and Warnings, seleccione el proceso que genera los mensajes a filtrar, por ejemplo, seleccionar Synthesis Messages para ver y posteriormente filtrar los mensajes generados por la herramienta de síntesis. A continuación, en la ventana principal de ISE se deben mostrar todas los Warnings, Infos and Error Messages generados por la herramienta de síntesis. 

4- Para seleccionar los mensajes ha ser filtrados, en el panel de la lista de todos los mensajes mostrados (en paso 3), seleccione (botón izquierdo del ratón) el mensaje que se desea filtrar. Si hay varios mensajes del mismo tipo, basta con seleccionar uno. A continuación, haga clic en el mensaje para filtrar y seleccione:
  • Filter All Instances of this Message - para filtrar todos los mensajes con el mismo nombre y número de la biblioteca de mensajes, independientemente del texto del mensaje.
  • Nota: hay otra opciones en el menú de filtrado:
    • Filter This Instance Only - para filtrar todos los mensajes con el mismo nombre de la biblioteca, número de mensaje y texto. Esta opción es para un solo mensaje, en particular, por ejemplo para un bit específico de un bús.
5- Sólo para estar seguro de que el filtro se ha configurado correctamente, haga Edit->Messages Filters. Una nueva ventana va aparecer en al cual se detalla el o los filtros configurados.


 En esta ventana se puede:
  • Remover el filtro: haga clic en el filtro y seleccione Remove o haga clic en el botón Remove Filter(s).
  • Desactivar temporalmente un filtro, haga click con botón derecho en el filtro y seleccione Disable (desactivar).
  • Activar nuevamente un filtro, haga click con botón derecho y seleccione Enable (habilitar).

6- Vuelva a ejecutar el proceso de generación de los mensajes a filtrar. Entonces, tanto desde la consola como desde el panel de error y advertencias los mensajes deben ser filtrados.

7- Nota: A pesar del filtrado todos los mensajes siguen estando disponibles. En el panel Design Summary seleccione All Implmentation Messages en la opcion Errors and Warnings. Los mensajes filtrados se mostrarán con un Yes (Sí) en la columna filtrada.



¡Precaución!

Cuando se suprime un mensaje, no se soluciona el problema.
No filtrar los mensajes para los temas que deben ser corregidos.
Filtro cuando se sabe lo que está haciendo. A continuación, puede centrarse en las advertencias que usted necesita para arreglar.

miércoles, 11 de marzo de 2015

Error: "cannot match operand(s) in the condition to the corresponding edges. . ." "An edge descriptor must be applied to an expression of size 1"


Introducción

Hace poco una alumna me pidió le revise su código Verilog porque tenía problemas y no encontraba como se originaba el error. Obviamente, la herramienta de síntesis que usaba generaba un mensaje de error, y obviamente ese mensaje daba muy poca idea de cual era el origen del problema. Lo primero que hice, y que a veces me da resultado, es sintetizar el código en la herramienta de la competencia, y .... lo mismo, mensaje de error encriptado. Lo segundo que normalmente se hace en estos casos es "googelar" el mensaje de error y ver que se encuentra al respecto.... No encontré nada... No me quedaba otra que estudiar el tema y ver que originaba el error. 
Detallo entonces debajo problema, mensajes y finalmente solución ....

Mensajes de Error Encriptados

ISE genera el siguiente mensaje de error: 

"ERROR:Xst:904 - "../../RTL_Src/semaforo.v" line 64: An edge descriptor must be applied to an expression of size 1."

El mensaje de error de Quartus: 

"Error (10200): Verilog HDL Conditional Statement error at semaforo.v(64): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct"

Las líneas del código correspondiente al número de línea indicado por el mensaje de error son las siguientes: 

 

A simple vista no se ve nada raro en el código. Revise muchísimas veces cada instrucción, cada simbolo, cada nombre y todo se veía perfectamente bien. 
Por supuesto una de las cosas que hice fue, por ejemplo, ir a la referencia del mensaje de error generado por la herramienta. En el caso del ISE el error es Xst:904, 

al hacer doble click en el link del error aparece: 
 

 
 Que ayuda, no? !!!

Quartus, directamente no tenía un link o explicación del error más allá del mensaje en sí. 
Bueno, después de dar tantas vueltas, como siempre la solución era muy sencilla. En realidad el problema no estaba en el código en sí, sino en la definición de clk y rst

Estas son las primeras lineas del código donde están definidas las E/S: 



Se dan cuenta del problema ?..... 

PROHIBIDO seguir leyendo sino encuentran el error :) ....

Por ahorrarse unas líneas de código, clk y rst fueron definidos en la misma línea que los vectores de dos bits sensor y boton.... por lo que clk y rst en realidad están definido como vectores de dos bits, por eso la instrucción negedge o posedge no puede determinar cual edge ejecutar. 

Como siempre una vez encontrado el error, uno dice: "Como no lo encontré antes!", "Que facil la solución", etc. etc, ... Lo que sí me parece extraño es que los compiladores no puedan generar un mensaje de error más sencillo, con mejor indicación del problema y una mejor guía de la solución.

Bueno, espero que les sea útil este artículo. 




 




miércoles, 22 de octubre de 2014

Diseño Jerárquico - Components / Port Map / Generic Map

Introducción

VHDL es extremadamente potente cuando un gran sistema se divide en sub-sistemas individuales, pequeños, y luego se va creando el sistema mediante la conexión de los componentes individuales. algunos les llaman sub-sistema, sub-componentes, otros sub-modulos, etc. también se le llama diseño top-down a este modo de dividir en partes pequeñas un sistema complejo. 

Para poder construir un componente complejo a partir de diversos sub-componentes, VHDL tiene un par de instrucciones que facilitan este proceso: declaración de componente, e instanciacion de componente. 

Declaración de Componentes 

Para usar un componente ya definido (entity/architecture), que va pasar a ser un sub-componente, en un nuevo componente es necesario primer declarar el componente a usar, y luego instanciarlo. Una declaración de componente simplemente específica la interface de E/S del componente mediante el uso de los puertos de E/S (I/O ports),  y los generics.   

-- declaracion de component
component register
  generic(bus);
  port (
    clk: in  std_logic;
    rst: in  std_logic;
    d_b: in  std_logic_vector(bus-1 downto 0);
    reg: out std_logic_vector(bus-1 downto 0)
       );
end component;


Nota: cuando la cantidad de declaración de componentes sea un número considerable, es aconsejable declarar los componentes en un paquete. De este modo el código en sí queda mas ordenado, limpio, y fácil de seguir. De todos modos a partir de VHDL-2008 no hace falta la declaración de componentes si la sintaxis de la instanciación de componentes es similar a la que se detalla en el ejemplo debajo. 


Instanciación de Componentes

Específica como las E/S del componente declarado (usando la declaración de componente explicada previamente), son conectadas en el diseño en que se utiliza el componente.


-- a)instanciacion de componente con asociacion posicional

U1: register port map (sys_clk, sys_rst, data_bus, reg_data);


-- b) instanciacion de componente con asociacion por nombre

U1: register port map (

                 clk => sys_clk,
                 rst => sys_rst,
                 d_b => data_bus,
                 reg => reg_data

                   );

-- c) instanciación en VHDL-2008 (sin declaración de componente)
U1: entity work.register port map (
                 clk => sys_clk,
                 rst => sys_rst, 
                 d_b => data_bus,
                 reg => reg_data
                   );


En la instanciación por posición, la lista de conexiones se hace en el mismo orden en que los puertos fueron declarados en la entidad del componente instanciado. 
Se aconseja el uso de asociación por nombre, ya que es menos propensa a errores. En esta caso también se aconseja separar las asociaciones por funcionalidad mas que por si son entradas o salidas. 


Ejemplo Sencillo 




library ieee;
use iee.std_logic_1164.all;

entity GATING is
  port (A, CK, MR, DIN: in  std_logic;

        RDY, CTRLA    : out std_logic);

end GATING;

architecture STRUCT of GATING is

component AND2
  port(  X, Y: in  std_logic;
         Z   : out std_logic);
end component;
component DFF
  port (D, CLOCK: in  std_logic;
        Q, QBAR : out std_logic);
end component;
component NOR2
    port ( DA, DB: in  std_logic;
           DZ    : out std_logic);
end component;
signal S1, S2: std_logic;

begin
D1: DFF  port map (A, CK, S1, S2);
A1: AND2 port map (x => S2, y=>DIN, Z => CTRLA);
N1: NOR2 port map (S1, MR, RDY);
end STRUCT;


Salidas no Usadas

En caso en que una salida del componente instanciado no se use cuando se instancia el componente, se debe explícitamente usar la palabra clave open para especificar que esa salida se deja abierta, no se utiliza, por lo que si es posible el sintetizado puede optimizar la lógica correspondiente. 

Entradas no Usadas

En caso en que una entrada del componente instanciado no se use cuando se instancia el componente, se debe explícitamente fijar un valor lógica a dicha entrada. Para ello se puede asociar la entrada no utilizada con '1' o '0'. 


Generic Map


El generic es un valor constante usado para describir en forma parametrizada una entidad. Ahora bien, diferentes instanciaciones de una misma entidad pueden tener diferentes valores de generic, para ello se usa el generic map.
Del mismo modo que antes, en caso de haber mas de un generic se puede usar asociación por posición o asociación por nombre. 
Ejemplo: 

entity registro_dff
  generic(reg_width: positive);
  port(
    rst,clk: in  std_logic;
    d, q   : out std_logic_vector(reg_width-1 downto 0);
     );
end entity registro_dff;
. . .
architecture ejemplo of registro_dff is
....
....
end ejemplo; 

-- instanciacion de registro_dff en otra entity
....  architecture test of registro_bus is
constant width_8 : positive:= 8;
constant width_16: positive:= 16;
signal d8, q8  : std_logic_vector(7 downto 0);
signal d16, q16: std_logic_vector(15 downto 0);
. . .

begin
  ff8: registro_dff generic map(width_8)
           port map (rst, clk, d8, q8);
  ff16: registro_dff generic map(width_16)
            port map (rst, clk, d16, q16);
. . .

end test;


lunes, 10 de diciembre de 2012

Personalizando el uso de ISim

Introducción


El simulador ISim puede fácilmente ser personalizado a fin de facilitar las tareas de visualización y depuración del diseño bajo test.

Procedimiento


Ejecutar el test bench como normalmente lo ejecuta.
Modifique las señales mostradas en el visualizador de formas de ondas de acuerdo a lo que necesite. Algunas de las opciones que brinda ISim son las siguientes:
  • Mover las señales a fin de juntarlas por funcionalidad. Seleccione la señal a ser movida con un simple click sobre la señal, luego mantenga el botón izquierdo de mouse apretado y arrastre la señal hacia arriba o hacia abajo.
  • Cambiar de color de la forma de onda. ISim ofrece la opción de cambio de color de la forma de onda de cada señal. Para ello simple click en la señal a cambiar el color, para seleccionarla, y luego presione botón derecho, y seleccione Signal Color, y luego el color que quiera usar para esa señal en particular. Este cambio de color es muy útil para señales que en cierto modo son de referencia para otras señales, pudiendo ser identificadas fácilmente en el conjunto de todas las señales.
  • Inserción de divisor de grupo de señales. Una vez realizado el paso 1, es conveniente colocar un titulo que de alguna idea de la funcionalidad de las señales. Para ello coloque el icono del mouse donde desea colocar el titulo del grupo de señales, presione botón derecho del mouse, y seleccione New Divider, y escriba el titulo correspondiente. Puede colocar tantos divisores como necesite.
  • Cambio de número relacionado a buses. Por cada bus se puede  seleccionar distinta representación del número correspondiente. Por ejemplo, se puede seleccionar Hexadecimal, Decimal, etc.
  • New Virtual Bus, permite juntar señales y formar un bus que solo es válido en la simulación.

Una vez realizados todos los cambios que desee, grabe esa configuración haciendo File->Save as. Escriba el nombre correspondiente, y se le agrega la extensión .wcfg.
Ahora bien, para usar esa configuración cada vez que se invoque el simulador debe hacerle saber al simulador que use esa configuración ya grabada en vez de la que usa por defecto. Seleccione Simulate Behavioral Model, y luego presionando botón derecho seleccione Process Properties. Tal como se ve en Figura 1.




Figura 1 - Acceso a las opciones del simulador

Una vez abierta la ventana de propiedades del ISim, haga clikc en la opción Use Custom Waveform Configuration File, y luego en la opción Custom Waveform Configuration File, navegue para agregar el archivo grabado en el paso anterior, tal como se puede observar en Figura 2.

Figura 2 - Configuración del simulador para usar la plantilla creada

A partir de ahora cada vez que se invoque ISim, se abrirá con la configuración grabada. 

Útil? te sirve de algo este blog? Avisame !!!  :) 

domingo, 28 de octubre de 2012

Replicación de Lógica - Inserción de Buffer - Alta Cargabilidad (High Fan-Out)

Introducción

Entre las tantas tareas que llave a cabo la herramienta de síntesis, hay una que se encarga de revisar la cargabilidad (fan-out) de cada señal lógica.Por defecto existe un número límite máximo de cargabilidad permitido. Este numero básicamente depende de la familia del FPGA con que se este trabajando. Por supuesto existe la opción de incrementar ese número, aunque no es lo mas aconsejable. La mejor solución para casos en que la cargabilidad de una señal sea mayor a la permitida, es lo que técnicamente se llama replicación de la lógica que genera la señal de tan alta cargabilidad. La cargablidad de cada registro, compuerta lógica y cualquier otro elemento lógico es analizado por el compilador de la herramienta de síntesis. Si el numero de cargabilidad encontrado supera al establecido por el diseñador, el compilar replica el nodo fuente de la señal hasta que el número de cada copia esté por debajo del número máximo de cargabilidad permitido. 

Cargabilidad (Fan-out)

Fan-out es definido como el número máximo de entradas de componentes lógicos que pueden ser conectadas con la salida de otro componente lógico. De acuerdo al diseño o circuito que se implementa algunas señales internas del mismo (salidas) se conectan a las entradas de otros componentes. Esta cantidad de conexiones puede ser un número desde 1 hasta un numero muy alto (por ej. 10000), este es el números que se conoce como fan-out. No hace falta que uno sea el que lleva la cuenta de la cargabilidad de cada señal, todas las herramientas de síntesis detallan en su reporte las señales que tienen un alto fan-out. 
Por qué existe un número máximo de fan-out? El número conexiones máximas están limitadas,  por un lado, por la degradación que puede tener la señal de del alta cargabilidad debido a que la principal carga que ve la salida es la capacitancia de entrada de los componentes a los que está conectada; así mientras mas conexiones tiene la salida, más capacitancia, más tarda en subir (rise-time) y en bajar (fall-time) la señal. Al tardar mas en subir y en bajar, la señal sufre un retardo generado solo por la cargabilidad, de este modo el rendimiento del sistema puede verse reducido. Finalmente, en el caso de los FPGAs, otro problema de una señal con un número alto de fan-out es que crea dificultades para rutear la señal dentro del FPGA, a no ser que se use una ruta dedicada para la señal de alta cargabilidad. 
Normalmente las herramientas de síntesis de los distintos fabricantes tienen un valor de fan-out para todas las señal (valor global) configurado por defecto. Sin embargo, este valor puede ser sobrescrito usando ya sea restricciones en el archivo correspondiente, (.sdc para Altera; .ucf para Xilinx), o usando atributos de síntesis, cuyo nombre depende de la herramienta de síntesis que se use.  


En el caso de Synplify, la herramienta permite configurar el valor de fanout máximo desde una ventana de configuración: 
Project -> Implementation Options -> Device

en la opción Fanout Guide se muestra el numero máximo de fanout.




El valor configurado para fanout, se aplica a TODAS las señales del diseño, se por ello se lo denomina fanout global. Tal como se explico anteriormente este valor no puede ser demasiado alto, pero tampoco demasiado bajo. En este último caso se corre el riesgo que la herramienta de sintesis duplique lógica o inserte buffers sin realmente necesitarse. Ambos extremos afectan el ruteo y el rendimiento del diseño. 
Para sobrescribir el fnaout global e imponer un fanout distinto en un mas bajo nivel se puede usar el atributo:

syn_maxfan 

Este atributo se aplica a distintos niveles de jerarquía del diseño, descripto en el siguiente cuadro: 


Cuál es la diferencia entre límite duro y blando? 
En el limite blando la herramienta puede o no puede replicar la logica o introducir un buffer, una vez superado el valor límite. En el caso de aplicar syn_maxfan a un registro por ejemplo, si se supera el valor de fanout configurado por el atributo SI o SI la lógica es replicada o se agrega un buffer a la señal.  
A continuación se presenta un ejemplo de un valor alto de fanout que afecta el rendimiento máximo del sistema. Como puede apreciarse el retardo de ruteo es excesivamente largo, principalmente debido a un muy alto valor de fan-ou (seguramente también esta señal no esta usando un ruteo dedicado). 


Esta señal, sig, es un típico caso en el que un alto fanout está afectando la frecuencia máxima de funcionamiento del sistema, por lo que se debería replicar la lógica generada de esa señal.

Quartus Configuración y Atributo

El atributo que controla el valor de fanout máximo en la herramienta de síntesis del Quartus II maxfan
El valor global de fanout se configura en en el Assignment Editor

XST Configuración y Atributo

El atributo que controla el valor de fanout máximo en la herramienta de síntesis XST del ISE de Xilinx se denomina max_fanout
El valor global de fanout se configura en: 
Process -> Properties -> Xilinx Specific Options -> Max Fanout

Detalles Lógicos

La herramienta de síntesis a fin de cumplir con los requisitos del valor máximo de fanout, puede hacer dos cosas: 
- replicación de lógica
- introducción de un buffer

 

Replicacion de Lógica

Cuando el fanout de un registro o una lógica combinacional supera el valor configurado, la herramienta de síntesis reduce el fanout al replicar la lógica de salida, ya sea secuencial o combinacional.

 

Introducción de Buffer

Un buffer es introducido por la herramienta de síntesis cuando una señal de entrada al FPGA tiene un alto fanout. 

 

Replicación Manual

Teniendo en cuenta que no todas las señales con alta cargabilidad originan problemas de bajo rendimiento, se puede proceder a una replicación manual del componente con una alta cargabilidad. Para ello en el código VHDL o Verilog se describe el componente las veces que sea necesario. Un punto muy importante en estos casos, es el uso de atributos de síntesis para prevenir que la lógica replicada sea optimizada por la herramienta de síntesis. Para ello se usan atributos tales como syn_preserve, syn_keep (en el caso de usar Synplify).


Excepciones

Como siempre ocurre hay excepciones a estas reglas y algunas son las siguientes:
  • Se puede 'exigir' a la herramienta de síntesis que use un 'buffer' en lugar de replicar la lógica. En el caso de Synplify esto se logra configurando el atributo syn_replicate a valor lógico '0', ya sea globalmente, o sobre el modulo o sobre un registro en particular. Este atributo previene la replicación, por lo que el software usará buffers para evitar los problemas relacionados con un fanout muy elevado
  • Para especificar que un puerto de entrada, por ejemplo una entrada de reloj, no sea usada con un buffer, se puede usar el atributo syn_noclockbuf, sobre esa entrada. Esto se usa comúnmente cuando se esta muy al limite con el numero de buffers globales y se necesita el buffer para una senal que no tiene un alto fanout pero que tiene una restricción de tiempo muy critica. 
  • Para casos en que el rendimiento del sistema no se muy crítico, es decir cuando la frecuencia de trabajo del sistema es baja o muy baja, se puede directamente evitar cualquier replicación de lógica o introducción de buffer al configurar el valor de fanout a un numero muy alto.  
  • Otros atributos que se pueden usar para que la lógica no sea replicada y en su lugar se introduzca un buffer, son los atributos syn_keep y syn_preserve. syn_keep es usado cuando se quiere mantener una señal, mientras que syn_preserve se utiliza para preservar un registro. En ambos casos si se supera el numero máximo de fanout, un buffer sera introducido en lugar de replicar la lógica.
  •  

Conclusión 

Es importante resaltar que las señales con alta cargabilidad en un diseño  no deberían ser tocadas a menos que esté en riesgo el rendimiento del diseño, es decir que la técnicas detalladas mas arriba se deberían usar en caso que la señal que tiene alta cargabilidad este afectando la frecuencia máxima a la que se desea funciones el diseño
La cargabilidad de las señales es detallada en los distintos reportes presentados por la herramientas de síntesis, ya sea Synplify, Quartus, XST, etc. En función de ese número y de que si se trata de una señal que es crítica para el máximo rendimiento del diseño, es que se deben aplicar las técnicas presentadas en este blog, para sea replicar la lógica o insertar un buffer.

viernes, 6 de julio de 2012

Lazos Combinacionales


Introduccion

Lazos combinacionales son estructuras lógicas que contienen realimentación sin ningún elemento sincrónico en el camino. Normalmente los lazos combinacionales provocan inestabilidad y sistemas pocos confiables, violando los principios de diseño sincrónico al establecer un lazo de realimentación sin registros. 

Porqué? Cómo se genera un lazo combinacional?

Un lazo combinacional es implementado en hardware cuando en el código VHDL escrito una señal que está del lado izquierdo de una instrucción de asignación (a la izquierda del símbolo <=) también aparece en la expresión aritmética/lógica del lado derecho de la instrucción de asignación (a la derecha de <=); siempre y cuando se esté describiendo lógica combinacional. Por ejemplo las siguientes líneas de código generaran un lazo combinacional si se escribe en un proceso combinacional o directamente como una instrucción de asignación concurrente.
  
1 acc <= acc + data;
2
3 Z <= Z nand B;
4
5 cnt <= cnt + 1;

 

Sin embargo es importante, muy importante, aclarar que si estas mismas líneas de código son escritas dentro de un proceso controlado por reloj, se generara la respectiva lógica secuencial; debido a que el reloj del proceso almacena el valor correspondiente por un ciclo de reloj, de este modo no existe una realimentación combinacional.

Hardware

La siguiente figura representa un esquema de un lazo combinacional:



Como se ve en la figura, la salida de la lógica combinacional se realimenta a si misma sin ningún tipo de registro en el medio. Este tipo de esquema lógico, normalmente no se desea, no es lo que se desea implementar, por ello la herramienta de síntesis genera una advertencia (warning) tal como se detalla en el siguiente ejemplo.

 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3
 4 entity lazo_comb is
 5   port(
 6     a: in  std_logic;
 7     z: out std_logic);
 8 end lazo_comb;
 9
10 architecture beh of lazo_comb is
11
12  signal y: std_logic;
13
14 begin
15     z <= y; 
16
17 process(a,y)
18  begin
19     y <= y nand a;
20 end process;
21
22 end beh;

La herramienta de síntesis, Synplify en este ejemplo, genera el siguiente mensaje de advertencia para este código:


El mensaje ‘found combinational loop at y’ significa que la señnal ‘y’ es realimentada combinacionalmente tal como se puede apreciar en el diagrama RTL de la respectiva implementación del código descrito:


  
A continuación se puede ver la simulación del sistema descrito arriba.



                Esta figura merece un detallado análisis. En primer lugar la primer ventana (de arriba hacia abajo) grafica las formas de ondas de las señales del sistema cuya principal expresión es la de la línea 24 de la segunda ventana. La tercer ventana, Transcript, detalla un error de simulación, diciendo que el limite de iteraciones del simulador fue alcanzado a los 50ns y no se llego a ningún valor estable. Es decir que el sistema empezó a oscilar y se quedo oscilando. El numero de iteración limite es programable en ModelSim (Simulate->Runtime Options), y en la mayoría de los simuladores. Por defecto este valor es de 5000. Viendo mas en detalle la parte inferior de la ventana donde se grafican las formas de ondas, se puede leer que el numero de Delta alcanzado es de 5000, que es justamente el numero limite de iteraciones configurado. Han transcurridos 5000 Deltas y aun el sistema no es estable.  
Otro punto importante a considerar en este ejemplo es el hecho de lo importante que es simular un sistema aun cuando sea muy simple. Suponiendo que hubiéramos directamente configurado el FPGA sin haber realizado la simulación (ya que la herramienta de síntesis nos da solo un ‘warning’), hubiéramos visto que la salida del sistema no era estable; y hubiéramos perdido una considerable cantidad de tiempo tratando de ver porque la salida no es estable
         En diseños con una gran cantidad de código a veces es muy fácil cometer errores como el del código descrito arriba. Por ello, hay que seguir un cierto orden en la escritura del código, tratando de mantener un cierto flujo de datos, por ej. de derecha a izquierda.
            En casos en que deliberadamente se desea implementar cierta lógica con un lazo combinacional tener en cuenta:
  • Comentar suficientemente el código de modo que se puede fehacientemente conocer la razón de existencia del lazo. 
  •  Realizar todas las simulaciones posibles, primero en PC y luego en hardware para comprobar que aun con la existencia del lazo el sistema sigue funcionando correctamente.
       Otro punto importante a tener en cuenta cuando deliberadamente se implementa un lazo combinacional, es que la herramientas de análisis de tiempo estático (Static Taming analysys, STA) normalmente incrementan por un valor (2-8 veces) el periodo mínimo cuando encuentran un lazo combinacional. Por ello, en estos casos se debería decirle a la herramienta STA que ‘ignore’ ese camino en particular. La sintaxis para el caso de Quartus (Altera), es ‘set_false_path’ (recordar que las herramientas de Altera usan constraints con las sintaxis de Synopsys; para ISE (Xilinx) use TIG con su respectiva sintaxis.