lunes, 27 de junio de 2016

Frecuencia Máxima de un Sistema Digital Sincrónico (Básico)

Introducción 

Comúnmente se expresa que un sistema puede correr satisfactoriamente a 100MHz, o a 133MHz o cualquier otra frecuencia. Qué significa esto? Porqué a esa frecuencia como máxima frecuencia? Quién fija ese límite en un circuito digital? y Cómo se obtiene 6 calcula, ese número? ? Muuuchas preguntas para contestarlas en un simple blog, pero... haré lo que pueda para contestarlas . . .  :) .

Periodo Mínimo
En primer lugar recordemos que el periodo de reloj de un sistema es el que 'marca el paso' en el sistema. Si el periodo es largo, el sistema da pasos (entrega resultados/valores) a pasos grandes (sistema lento), si el periodo del reloj es pequeño, el sistema entregará resultados a pasos mas cortos, es decir mas rápidamente. 
Recordemos también que la frecuencia de funcionamiento de un sistema es la inversa del periodo de ese mismo sistema: F = 1/T (periodo). Por ello para encontrar la máxima frecuencia debemos encontrar el periodo mínimo . . . 


Cómo calcular u obtener el periodo mínimo?
Bien, en un sistema digital el periodo mínimo está compuesto por los retardos MÁXIMOS de los componentes sincrónicos, de los componentes combinacionales , y de las interconecciones entre ellos.
Veamos que significa esto: primero, en un sistema hay muchos caminos sincrónicos (camino de conexión entre flip-flops), pero el que es de interés para el calculo del periodo mínimo es el camino (path) MAS LENTO de todos, es decir el que tiene los retardos MÁXIMOS. El camino mas lento también es llamado camino CRITICO (critical path).

Componentes del periodo mínimo: 
  1. Retardo Sincrónico: cuanto se demora en estar estable el dato a la salida de un flip-flip luego del flanco activo del reloj.
  2. Retardo combinacional: está compuesto por los componentes no sincrónicos, pueden ser compuertas lógicas, mux, decodificadores, LUTs (en el caso de un FPGA), etc, del camino crítico. Puede haber mas de uno de estos componentes; el retardo de cada uno se suma para lograr el retardo total. La cantidad de componentes combinacionales en el camino critico es normalmente informado en el reporte de frecuencia máxima como 'niveles lógicos' (logic levels). Si se informa que el 'logic level' es 5, significa que en el camino critico hay 5 componentes lógicos combinacionales. 
  3. Retardo de ruteo o de conexiones en el camino critico:
    1. Entre la salida del componente sincrónico (flip-flop) y la entrada a los componentes combinacionales.
    2. Entre los componentes combinacionales.
    3. Entre la salida de los componentes combinacionales y la entrada del flip-flop.
  4. Tiempo de establecimiento del flip-flop donde termina el camino critico. El dato de entrada tiene que estar un tiempo de establecimiento (dado por la hoja de datos) antes de la llegada del flanco activo del reloj, a fin de evitar problemas de metaestabilidad.
  5. Margen de periodo: normalmente los valores de los retardos máximos de los puntos anteriores pueden estar afectados por lo que se llama PVT (process, volume, temperature) y los valores dados por la hoja de datos no son los que realmente tenga el circuito en funcionamiento. Por ello se agrega un cierto margen para asegurarse la estabilidad del sistema.  
Como bien se dice, una imagen vale mas que mil palabras, la siguiente figura muestra gráficamente lo anteriormente descrito en palabras:


En ésta figura los tiempos detallados son los siguientes: 
  • Tco: retardo sincrónico, comúnmente llamado 'clock to output'. 
  • Rr  : retardo de ruteo.
  • Rc  : retardo total de la lógica combinacional, que puede tener varios niveles.
  • Tsu: tiempo de establecimiento del flip-flop. 

Con todo esto podemos ahora describir la fórmula para calcular el periodo mínimo que nos va dar la frecuencia máxima de funcionamiento del sistema: 


El 10% de margen se calcula sumando los otros retardos y sacando el 10% de esa suma, el valor obtenido se usa como margen de seguridad del periodo mínimo. 

Periodo Mínimo en FPGAs
Los softwares provistos por los fabricantes de FPGAs ofrecen herramientas que realizan el análisis de todos los caminos sincrónicos del sistema. Estas herramientas realizan lo que se llama un Static Timing Analysis (STA) y reportan el camino más críticos y los siguientes casos no tan críticos. Por ejemplo Altera Quartus provee TimeQuest, Xilinx ISE ofrece Timing Analyzer, Libero de Actel ofrece SmartTime. En un anterior post detallé la información dada por Timing Analyzer. 
A modo de ejemplo de la informacion proviste por una herramienta STA, se puede ver a continuación un ejemplo de la información de un camino critico dada por la herramienta TimeQuest de Altera. 


Analicemos ésta información: La primer columna muestra los tiempos de ya sea de una celda lógica o de un ruteo. La tercer columna detalla el componente o conexión motivo del retardo: el tiempo referenciado como CELL es el retardo combinacional de la celda lógica detallada en le última columna de la derecha. El tiempo IC se refiere al retardo de ruteo o de interconexión entre las celdas lógicas combinacionales. Como puede verse algunos retardos de IC es igual a 0.000; esto se debe al ruteo dedicado que existe dentro de cada bloque básico del FPGA. El retardo total de este camino mas critico, que es el periodo mínimo al que puede correr satisfactoriamente este sistema, es de 2.331ns. Solo como referencia: La información de la quinta columna detalla el componente lógico usado, y la ultima columna el nombre dado por la herramienta de Place and Route para asociar el componente lógico con el nombre usado en el código VHDL.  
Esta información es mas fácil de interpretar viendo el esquemático de éste camino. Tanto Altera, como Actel y Xilinx ofrecen esta vista. He preparado una figura que relaciona todo lo visto hasta acá, asociando el esquemático generado por la herramienta de análisis de tiempo y la figura anteriormente presentada. 

  
Como ya dije al principio este es un cálculo básico del periodo mínimo de un sistema; en un próximo blog trataré de ir mas en detalle teniendo en cuenta por ejemplo el corrimiento del reloj (clock skew), retardos del camino de datos, jitter del reloj, etc....
De todos modos espero que este post haya sido de utilidad (avisen si es así :) .
(version .pdf click acá :) )

lunes, 7 de marzo de 2016

Código Assembler del 'C' para el Zynq

Introducción


Para los que hicimos nuestros primeros programas para microprocesador en Assembler (algún tiempo atrás :) ) , aun hoy en día es lindo 'ver' el código assembler generado desde el 'C' que escribimos en nuestra aplicación que sera ejecutada en el Zynq. 
Pero, por otro lado, algunas veces es necesario escribir una rutina o una funcion directamente en Assembler, sobre todo cuando es necesario una muy alta frecuencia de funcionamiento/calculo. 
La herramienta SDK, que es parte del entorno Vivado de Xilinx, tiene un modo de 'ver' el Assembler generado desde el 'C'/

Uso de la Herramienta Xilinx Microprocessor Debugger (XMD) 


XMD es una herramienta que facilita la depuración (debug) y verificación de sistemas implementados en Dual ARM Cortex-A9 (también se puede usar con MicroBlaze y Power PC). 

SDK provee una consola llamada Consola XMD, donde se puede escribir un comando XMD para que sea ejecutado. Los comandos usados son del tipo Tool Command Language (Tcl). 

La Consola XMD se puede abrir de dos modos diferentes: 
  1. Cuando se activa la perspectiva Debug, la Consola XMD se abre automáticamente. 
  2. En la perspectiva C/C++, se debe hacer Xilinx Tool-> XMD Console. 
Una captura de pantalla de la Consola XMD (en la perspectiva Debug) es mostrada a continuación:


Tal como se puede apreciar, la Consola XMD es una típica consola Tcl, donde es posible ejecutar cualquier comando Tcl permitido por XMD. El comando a ejecutar se debe escribir a continuación del indicador XMD%.

Nota: hay una herramienta mas completa que 'casi' reemplazaría a XMD, que se llama Xilinx System Debugger Command-line Command-Line Interface (XSDB). SDK también provee una Consola XSDB (que será explicada dentro de poco). Sin embargo, aun hay comandos que solo están disponibles en la Consola XMD, tal como es el comando que veremos a continuación. 
 
Entonces, volviendo al objetivo de este post, para ser capaz de 'ver' el código Assembler generado desde el 'C', el comando XMD a escribir es el siguiente: 

arm-xilinx-eabi-objdump -S .elf

En la figura debajo se muestra el lugar donde se debe escribir el comando, y la sintaxis completa (notar el uso de doble barra atrás '\\'): 


Para ejecutar el comando se presiona . El resultado de la ejecución del comando se muestra en la siguiente figura, junto con algunos títulos indicativos de las distintas partes del archivo generado: 


El archivo es de un gran tamaño. Pero es fácil de seguir si se tiene algo de experiencia usando lenguaje Assembler. 

Bien, hasta acá llegamos con este post, espero que les sea útil..  :) 

miércoles, 2 de marzo de 2016

Error (en algunas versiones): "undefined reference to Xil_ICacheDisable"

Introducción


Cuando comencé mis primeros pasos con Vivado-SDK me encontré con un problema bastante raro, y aún hoy me preguntan por ese problema, así es que aquí lo publico. 
Resulta que tratando de hacer el proyecto mas simple de todos, el famoso Hello World, me encontré con 10 errores en el SDK... ! Como a pesar de seguir todos los pasos de distintos tutoriales puedo generar diez errores con el proyecto Hello World... ??!!

Encontrando y Solucionando el Problema


Siguiendo los pasos descritos en distintos tutoriales genere el proyecto Hello World en Vivado. Acá ven una captura de pantalla del diseño (creo que es lo mas simple que se puede hacer en Vivado ! :) ) ... : 


Una vez generado el diseño, seguí todos los pasos para primero Export Hardware, y luego invocar SDK
En el entorno SDK, cree una nueva Application Project basada en el patrón (template) Hello World. Luego ejecuto Build Project, y acá aparecen los errores: 


Entonces, lo primero que hago (lo que uno casi siempre hace :) )... es buscar ayuda en la web...., busqué, busqué, y ... nada encontré... Así es que empece a investigar por mi lado y descubrí lo que parece ser un 'bug' en la versión 2015.1 de Vivado: aún cuando la interface DDR no está configurada en hardware, es generada incompletamente en software. 

En un proyecto tan simple como el Hello World, no hay ninguna necesidad de usar la memoria externa DDR disponible en el ZedBoard. Por lo que no hay necesidad de habilitar la interface DDR en el Zynq. Sin embargo, para solucionar los errores presentados anteriormente es necesario habilitar la interface DDR, aún cuando no se vaya a realizar ninguna Rd/Wr en la DDR. 
Nota importante: otras versiones de Vivado no generar estos errores. 

Una vez que se  agrega la interface DDR (en el entorno Vivado, ver figura debajo) y se regenera el hardware y el Application Project, los errores no vuelven a aparecer cuando se ejecuta Build Project.


En un próximo post detallo como se fuerza al linker para usar la OCM (On Chip Memory) para ejecutar el Hello World.

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.

martes, 26 de enero de 2016

Uso de ' - ' (don't care) en VHDL

Introducción
El valor ' - ' (normalmente llamado don't care, o no importa) normalmente es usado en funciones booleanas para representar indistintamente un '1' o un '0'. Se usa principalmente para minimizar una función booleana al poder usar el valor lógico ('1' o '0') que resulta en una menor imeplementación de hardware. Sin embargo en VHDL el tipo std_logic define a ' - ' como un valor en si. Es decir no puede ser indistintamente '1' o '0' porque es ' - '. 
Veremos a continuación como se describe en VHDL una función en la que ' - ' puede tomar valor '1' o '0'. 
Nota: en alguna bibliografía se usa 'X' en lugar de ' - ' para representar el don't care. En VHDL 'X" es otro valor definido en el tipo std_logic, por lo que NO se debe usar para representar don't care. 'X' en VHDL es un valor 'don't know', o 'no sé'. 

' - ' como entrada en funciones Booleanas
Normalmente las funciones booleanas son representadas por una tabla de verdad que describe los distintos valores que se obtendrán en la salida de la función como respuesta a distintos valores de entrada. Veamos un ejemplo, la función de un decodificador con prioridad tiene la siguiente tabla de verdad: 


Fácilmente se puede observar que la salida de la función es '10' cuando I2 es '1', sin importar en lo mas mínimo el valor de I1 e I0. Así, la tabla de verdad se puede re-escribir de manera reducida teniendo en cuenta lo recién explicado, quedando expresada de la siguiente manera:


' - ' como salida en funciones Booleanas
En el caso de usar ' - ' como el valor que toma la función ante cierta condición de entrada, significa que realmente el valor de la salida 'no importa' que sea '0' o '1'. Aunque esto suene raro, como no va importar el valor de salida?!?!?!, en realidad se usa para los casos en que esa condición/valor particular de las entradas no es esperado, ni debería darse bajo ninguna circunstancia. 
Veamos en detalle la siguiente tabla de verdad

Para este caso cuando la entrada es '11' la salida puede ser '1' o '0'. Si, por ejemplo cuando se implementa la función, y se le asigna valor '0' para la combinacion de entradas '11', el mapa de Karnough de la funcion es el siguiente: 

Y la funcion resultante de la lectura del mapa es, f = a'b + ab'
Cuando se le asigna un valor '1', el respectivo mapa de Karnaugh es: 



y la función resultante: f = a+b . 
Esta ultima función requiere menos hardware, por ello el uso de ' - ' puede ser importante en casos en que el número de componentes lógicos (compuertas, LUTs, etc) sea clave en el diseño que se quiere implementar. 

Uso de ' - ' en VHDL
El valor ' - ' esta definido en el tipo std_logic. SIN EMBARGO, VHDL considera ' - ' como un valor lógico en si, totalmente diferente de lo explicado anteriormente. Es decir ' - ' no puede tomar valor '0' o '1' porque en sí tiene un valor, que es ' - '. 
Así por ejemplo el siguiente código evalúa siempre como falso, 

1      if data = "1- - 1" then ...;

porque nunca en hardware existirá el valor "1 - - 1". 

Veamos entonces como hacer para que ' - ' pueda, de algún modo, ser usado como es usado en el álgebra de Boole, pudiendo tomar valor '1' o '0'. 

Uso de ' - ' como entrada en código VHDL 
Usando los conocimientos de VHDL  (q se supone q tienes :) . . . ) la tabla de verdad del decodificador con prioridad se podría describir como:

1 y <= "10" when I = "1--" else --siendo I la concatenación de I2I1I0
2      "01" when I = "01-" else
3      "00" when I = "001" else
4      "00";

Escrito como está, este código NO describe un decodificador con prioridad, porque?,,, Bien, cuando este código es implementado la condición "1--" o la condición "01-" NUNCA es verdadera. Porque?,,, bueno físicamente en un circuito digital solo se tienen dos valores lógicos o '1' o '0'. Así, si por ejemplo la señal de entrada tienen un valor "111", ninguna expresión será verdadera y el valor asignado a Y será "00'. 
Una solución a este problema sería describir el decodificador con prioridad de la siguiente manera: 

1 y <= "10" when I(2) = '1' else
2      "01" when I(2 downto 1) = "01" else
3      "00" when I(2 downto 0) = "001" else
4      "00";

Este código se acerca mas a lo que estamos buscando, sin embargo la mejor solución es la siguiente: En el paquete numeric_std hay una función llamada std_match(), que básicamente realiza una interpretación de ' -' de acuerdo a lo q el diseñador espera, es decir trata el valor ' - ' del tipo std_logic como valor '1' o '0'. La función compara dos vectores de tipo std_logic_vector e interpreta ' - ' como un valor 'no importa', y da como resultado un boolean (F/T). Usando la función std_match() se puede re-escribir el primer ejemplo como: 

1      if std_match(data, "1 - - 1") then . . . .


Lo que hace la función std_match() es comparar el vector data con el vector "1 - - 1", evaluando como verdadero si el primer y el último elemento de data son '1', sin interesar los otros dos valores. 
Nota: std_match también puede usarse con tipos unsigned, signedstd_ulogic, std_ulogic_vector, y std_logic.  

Del mismo modo el código del decodificador con prioridad anterior puede re-escribirse así: 

1 use ieee.numeric_std.all;
2      ....
3
4 y <= "10" when std_match( I, "1--") else  
5      "01" when std_match(I, "01-") else
6      "00" when std_match(I, "001") else
7      "00";

Uso de ' - ' como salida en código VHDL
Es bastante común el uso de ' - ' en una salida. Normalmente se lo utiliza como el valor que se la asigna  a la salida cuando todos los valores de entradas han sido ya asignados y queda solo 'when others' , 'else' ,etc. Por ejemplo la tabla de verdad descrita anteriormente se puede describir en VHDL de la siguiente manera:

1 tmp <= a & b;
2 with tmp select
3     y <= '0' when "00",
4          '1' when "01",
5          '1' when "10",
6          '-' when others;

De este modo el sintetizador puede utilizar el '-' como '1' o '0' para optimizar el hardware a implementar.

Espero q' sirva de algo lo acá escrito.... 
Suerte ! 

Nuevo: bajá la versión pdf de este artículo haciendo click acá  ->  :)