jueves, 30 de diciembre de 2010

Error: Aggregate expression cannot be scalar type . . .


El mensaje de error:  " Aggregate expression cannot be scalar type ieee.std_logic_1164.std_logic" 

Puede tener diferentes fuentes. En este caso analizaremos el error asociado a la siguiente expresión:

dato_out(7 downto 0)   <=   data_shift(7 downto 0);

En realidad el problema acá es que algunos compiladores no permiten el uso de un 'rango' en lado izquierdo de una instrucción de asignación. Por lo que la solución es bastante sencilla, tanto como definir una señal 'temporaria' a la cual se la usara como intermedia para la asignación libre de error:


signal data_out_tmp: std_logic_vector (7 downto 0); 
. . . 
data_out_tmp <=  data_shift(7 downto 0);


data_out          <= data_out_tmp; 


Un error menos ! :) 


HapyyNew Year !
Feliz Año Nuevo ! 

martes, 14 de diciembre de 2010

Slack Positivo/Negativo ?

Slack = Tiempo Requerido - Tiempo de Arribo

Donde:

Tiempo Requerido: usualmente el periodo del reloj
Tiempo de Arribo: tiempo que tarda una señal en llegar a cierto punto.

Un Slack positivo de un valor n, significa que el tiempo de arribo al nodo en cuestión puede ser incrementado por n sin afectar el retardo general del circuito. Si todos los Slacks del reporte son positivos, de 10 !!!!
Contrariamente, un Slack negativo implica que el path es demasiado lento, y deberá ser 'acelerado' si se desea que el diseño trabaje a la frecuencia deseada. Si hay algun Slack negativo, mmmmm a trabajar... primero encontrar la razon (investigar el timing path presentado por el Post P&R Timing report), y después ver como se puede solucionar (pipelining, etc)

El valor del Slack es presentado por el post-P&R Timing Report. Generalmente el reporte ordena los Slacks de menor valor, comenzando con los valores negativos si hay, a los Slacks de mayor valor. La cantidad de información presentada depende del seteo de la herramienta. Por lo general, por defecto se muestran los primeros 5 o 10 paths con menor Slack, pero esta cantidad de paths a presentar es configurable por el usuario. Por ejemplo en ISE 12, seleccione Implement Design->Place & Route -> Generate Post_place & Route Static Timing. Presione botón derecho del mouse, y seleccione Properties. 'Number of Paths in Error/Verbose Report' es la propiedad a cambiar para seleccionar la cantidad de paths a ser mostrados durante el timing report.

Qué significa Timing Score en el Timing Report de ISE (Xilinx) ?

Cuando el proceso 'Place & Route' es ejecutado, se reporta un mensaje como el siguiente:

Timing Score: nnnn

donde nnnn es un numero que puede ser '0' o puede ser cualquier otro número.

Qué significa éste número?
El Timing Score representa el valor total que representa los análisis de los tiempos para todos las restricciones (constraints) y por cuanto las restricciones no se cumplen. Es decir, es la suma en picosegundos de TODAS las restricciones que no se cumplen. También se puede decir que es la suma del valor absoluto de TODOS los Slacks, cuando los slacks son negativos), expresados en picosegundos.
Mientras mas chico es el valor del Timing Score, es mejor el resultado.

Por todo lo dicho qué significa que el Timing Score sea igual a '0'??????

Significa que TODOS los timing constraints se cumplieron satisfactoriamente.

Ahora bien, la información dada por el Timing Score cuando éste numero es distinto de '0', no es muy útil. Por ejemplo, si se obtiene un Timing Score de 20,000; esto número puede significar:
a- Un simple path está fallando el timing constraint por 20ns.
b- 200 paths están fallando el timing constraint por 1 ns.
En el caso a) se puede asegurarse que el path que no cumple el timing por 20ns , seguro que fallara en Hardware. Mientras que en el caso b), el sistema 'puede' llegar a trabajar en Hardware, aunque no en los casos de bajo voltaje o alta temperatura.

Como conclusión, si el Timing Score es '0', todo bien ! ; si el Timing Score es != '0' (distinto de '0'), será necesario chequear en detalle el post P&R Timing Report para ver cual/es son los paths que no cumplen la(s) restricción(es).

miércoles, 3 de noviembre de 2010

Warning: "Port port_name hidden by declaration in architecture" o "Declaration hides port port_name"

Este es un Warning común, y que es difícil de resolver porque una primer lectura del mensaje no da mucha idea donde puede estar el problema. Sin embardo re-leyéndolo con cuidado, y con la ayuda de un buen diccionario de ingles :) .... , se puede tener una idea del problema.


Lo debería dejar como 'tarea para la casa ... ' , pero como me imagino q ya tienen demasiadas tareas lo resolveremos.....


"Port port_name hidden by declaration in architecture" => hay un puerto (port) de E/S, pues todos los ports son o de E o de S, no señal interna ! ..., que esta 'ocultado'/'escondido' por una declaración en la arquitectura. Es decir hay una declaración en la arquitectura que oculta el puerto de E/S... Q' instrucción de declaración puede haber en una arquitectura ??????? -> una declaración de señal interna (signal declaration). .... pero para q' oculte un port específico de E/S, deber ser q' accidentalmente hemos declarado una señal interna con el mismo nombre q' el port de E/S.... De este modo no se podrá acceder al puerto de E/S desde la arquitectura..... y por eso el compilador chilla con el grito.. .Warning.....


Muy    fácil????????????????  entonces el próximo lo deducen Uds :)




bye,

jueves, 28 de octubre de 2010

Añadir puntos de pruebas (probes) en FPGA Editor

Esta es una técnica aconsejada para usuario avanzados, recomendada cuando el tiempo de P&R del diseño es muy largo (>2 horas). 
Añadir puntos de pruebas puede ser algo de mucha ayuda cuando se necesita debug un diseño complejo. Dado que un FPGA es un dispositivo programable usualmente hay elementos disponibles que pueden ser usados luego de haber Place & Route el diseño. El caso típico es por ejemplo que se desee saber el valor lógico de una señal interna de un diseño, para ello se puede routear esa señal interna a algún I/O pin disponible y de fácil acceso para poder usar la punta del Oscilloscopio o Analizador Logico. Tambien puede ser útil para routear una senal interna a un LED del board que está conectado a un I/O pad específico. La herramienta FPGA Editor, parte del ISE, ofrece la posibilidad de seleccionar (probe) cualquier red interna y automáticamente rutear la(s) señales deseadas al I/O pin que se necesita.

Los pasos a seguir son los siguientes:
  1. Una vez Place & Route el diseño, doble-click en el proceso “View/Edit Routed Design (FPGA Editor).
  2. Una vez abierta la ventana de la herramienta FPGA Editor, de la columna de botones sobre la derecha  de la pantalla, presione el botón ‘probes’.
  3. En la ventana ‘Probes’ presione el botón ‘Add’ (primer botón sobre la derecha).
  4. Una nueva ventana aparecerá llamada ‘Define Probe’. Esta ventana tiene dos partes principales:  
    • La parte superior, ‘Select Net’, se refiere a las redes (nets) disponibles pare rutear. Recuerde que una vez que el diseño ha sido P&R algunas señales cambian el nombre, como asi también aparecen nombres como N3, N5, etc. En esta parte de la ventana se debe seleccionar la red deseada. 
    • La parte inferior, ‘Select Pin Numbers’,  se refiere a los I/O pines disponibles para rutear la red seleccionada en la parte a). Hay dos métodos para seleccionar el I/O pin (del menú ‘Method’), uno es automatico, la herramienta selecciona el pin (normalmente el que de menos retardo de ruteo); y el otro método es manual. En el Manual en la columna inferior izquierda, ‘Available Pins’, se selecciona el I/O pin y una vez seleccionado se lo ‘transfiere’ a la columna derecha, ‘Selected Pins’, presionando el botón ‘>’.
  5.  El proceso descripto en el punto 4. se puede repetir tantas veces como se necesite.
  6.  Una vez finalizado se presiona OK. En la ventana ‘Probes’ deberán ahora aparecer las redes seleccionadas, sus respectivos I/O pins y una estimación del retardo para alcanzar la salida desde el punto de conexión de la señal seleccionada.
  7. Es conveniente usar la opción ‘Save Probes’ para guardas los puntos de pruebas y sus pines asociados. En un futuro uso se puede usar la opción ‘Open Probes’ para abrir los puntos de pruebas anteriormente guardados. 
  8. ‘Close’ cierra la ventana ‘Probes’, retornando a la ventana del FPGA Editor.
  9. Ahora es necesario grabar los cambios realizados al original diseño. File-> Save o File-> Save As para cambiar el nombre. Por ejemplo rs_232_con_probes.ncd. De este modo se puede distinguir el .ncd original del .ncd con puntos de pruebas.
  10. El último paso es generar el respectivo archivo de configuración del FPGA, y descargarlo en el FPGA. Si ha usado un nombre diferente para el .ncd grabado (punto 9), se debe tener cuidado de generar correctamente el archivo de configuración. 


Espero q les sea de utilidad.....

sábado, 16 de octubre de 2010

Source Synchronous Clocking

Source-synchronous clock se refiere a una técnica usada en buses de alta velocidad para enviar/recibir datos entre dos dispositivos. Existe otro método llamado system synchronous que veremos en un próximo blog.
En el caso de un sistema source-synchronous, el dispositivo transmisor (source) envía el reloj junto con el (los) dato(s). De este modo el timing de los datos, unidireccionales, estan referenciados a este especifico clock (a veces llamado strobe) generado por el dispositivo origen (source).




En la figura de arriba el FPGA es el dispositivo de destino, sin embargo, en otra situación el FPGA puede ser el dispositivo transmisor.
Este tipo de clocking es común en interfaces de alta/muy-alta velocidad como el Intel Front Side Bus, HyperTransport, SPI-4.2 y la mas común DDR.
Ventaja: dado que el reloj y los datos son generados por un mismo dispositivo, variaciones en los retardos de  propagación generados por variaciones de PVT (Process Voltage Temperature) serán los mismos para el reloj y los datos. Completamente diferente a lo que suele ocurrir cuando un tercer dispositivo genera el reloj del sistema.
Desventaja: la principal es la creación de un dominio de reloj en el dispositivo receptor separado del reloj principal del mismo. Como consecuencia es necesario un bloque de sincronización en el receptor para transferir el dato recibido, sincronizado con el reloj del transmisor, al dominio del reloj receptor (pues generalmente la lógica del receptor trabaja a una frecuencia no relacionada para nada con la frecuencia del reloj del source synchronous). Para muy altas velocidad problemas de cross-talk y skew pueden aparecer.
Si bien este sistema añade mas lógica, comparado con un sistema de reloj general, permite trabajar con altas velocidades transmisión. Por ejemplo 622 Mbit/s para SPI-4.2.


Relación dato-reloj
Hay dos opciones de relación reloj-dato definidas de antemano por el protocolo del bus source synchronous con que se esté trabajando.
Por ejemplo, cuando se lee una memoria DDR el dato está sincronizado (edge-aligned) con el flanco del reloj. Así, los datos a la salida de la memoria se ven como en la siguiente figura:


Por lo que para realizar una captura correcta del dato, en el receptor normalmente se hace pasar el reloj por un elemento de control de reloj, tipo DCM en los FPGAs de Xilinx, para desplazar (shitf) el reloj 90 grados y asi capturar el dato en los DDR flip-flops sin problema.
En otros protocolos, SPI-4.2 por ejemplo, dato y reloj tienen la siguiente relación:


El reloj esta desplazado (normalmente centrado) con respecto al dato, por lo que el receptor puede usar perfectamente el reloj del transmisor para efectuar el registro de los datos. Sin embargo, en algunas interfaces con este tipo de relación reloj-dato, se usa un PLL o DCM para desplazar (phase offset) la entrada de reloj de modo de hacer un ajuste 'fino' del flanco de reloj para la mejor captura del dato.


Independientemente de la relación reloj-dato con que se trabajo SIEMPRE se deben usar los flip-flops localizados en los bloques E/S, ya sea para transmitir o para recibir. Por ejemplo para el caso de Xilinx se debe usar un contraint como el siguiente:

INST *abus_ddr_* IOB=TRUE;# Fuerza el uso de IOB 
                          #flip-flops en las señales *abus_ddr_*


Para no aburrirlo y que no se haga muy largo este post, seguiré con System-Synchronous en el próximo.... (cdo? ... no se :) :) )

jueves, 7 de octubre de 2010

Entendiendo (parte de) la Información dada por Timing Analyzer




Supongamos que se tiene un diseño que necesitamos que corra a una frecuencia de unos 100MHz (10 ns periodo). Un ejemplo de constraint para el reloj es el siguiente: 

NET "sys_clk_100" TNM_NET = sys_clk_100;
TIMESPEC TS_sys_clk_100 = PERIOD "sys_clk_100" 10 ns HIGH 50%;

Fijando un periodo de 10 ns para la señal de reloj sys_clk_100. 
Ahora bien, una vez que se ejecuta en el ISE el proceso "Analyze Post-Place & Route Static Timing",  un montón de información con respecto al timing del diseño se detalla en la respectiva ventana de la herramienta. Entender parte de esa información, la que creo que la parte mas importante, es lo que deseo explicar a continuación: 
Timing Analyzer (TA) califica la información en función de los diferentes contraints que se hayan especificado en el diseño. Por ahora estudiaremos la que nos interesa y es la referida al constraint que detallamos arriba. Asi, Taming Analizar detalla la siguiente información referida a ese constraint: 

------------------------------------------------------------
Timing constraint:
  TS_sys_clk_100=PERIOD TIMEGRP "sys_clk_100" 10 ns HIGH 50%;

 1459 items analyzed, 0 timing errors detected. (0 setup errors, 0 hold errors)
 Minimum period is   4.207 ns.
------------------------------------------------------------

Detallando que han sido analizados 1459 diferentes caminos relativos a ese reloj, con 0 errores de timing, pudiendo usarse un reloj de periodo mínimo de 4.124 ns (máxima frecuencia). 

Debajo de esa información TA empieza a detallar los caminos referidos a ese reloj, listando el de mayor retardo primero. Se detalla a continuación como se interpreta la información que presenta TA, en este caso para un camino específico. 

------------------------------------------------------------------
Slack:                  5.793ns(requirement-(data path - clock path skew + uncertainty))

  Source:               baud_gen/count_x16_13 (FF)
  Destination:          baud_gen/count_x16_4 (FF)
  Requirement:          10.000ns
  Data Path Delay:      4.207ns (Levels of Logic = 3)
  Clock Path Skew:      0.000ns
  Source Clock:         sys_clk_100_IBUFG rising at 0.000ns
  Destination Clock:    sys_clk_100_IBUFG rising at 10.000ns
  Clock Uncertainty:    0.000ns
-----------------------------------------------------------------

La información más importante se refiere a si el camino ha cumplido con el requerimiento de tiempo. Esta información aparece en la primer línea y es definida como Slack. Si el Slack es positivo, significa que la ruta detallada cumple el requerimiento de tiempo por el número especificado como Slack. Si el Slack es negativo, entonces esa ruta viola el tiempo requerido por el número specificado en el Slack. Al lado del número de Slack se detalla la ecuación usada para calcular el Slack (mas abajo se explican los valores de la misma).
La próxima línea en el reporte es Source. Este es el punto de comienzo del camino analizado, normalmente un componente, en este caso es un flip-flop (FF), pero puede ser otro componente como RAM, PAD, LATCH, etc.
Sigue la línea de Destination, que es el punto final del camino analizado, y corresponde en este caso a un flip-flop (FF).
La siguiente línea se refiere a Requierement. Este es un número calculado con el constraint del periodo del reloj y el tiempo de los flancos del reloj. El reloj de destino y el fuente en este caso son los mismos, por lo que el Requirement es igual el periodo del reloj fijado en el constraint respectivo. Si el reloj de destino o el reloj fuente usaran el flanco de bajada del reloj, el valor de Requierement hubiera sido 5 ns, o sea la mitad del período fijado por el constraint.
EL Data Path Delay es el retardo del camino del dato desde la fuente hasta el destino. Normalmente este valor es la suma del retardo de ruteo más el retardo de la lógica. El retardo de la lógica se mide en niveles de lógica que normalmente es implementada en LUTs, y en este caso se tienen 3 niveles de lógica. Este retardo NO incluye clock-to-out del flip-flop o setup time.
Clock Skew es la diferencia entre el tiempo que la señal de reloj llega al flip-flop fuente y el tiempo en que llega al flip-flop destino. En este caso no hay diferencia, por lo que el valor es 0 ns.
Source ClockDestination Clock reporta el nombre del reloj en la fuente o destino. También incluye si el flanco de reloj es positivo o negativo y el tiempo en que ocurre el flanco.
Clock Uncertainty se refiere a un parámetro de tiempo que se fija como constraint basado en el jitter del reloj y al error de phase que pueda tener el reloj (en breve escribiré al respecto). En este caso no se ha definido ningún valor en el constraint (restricción) por lo que es igual a 0 ns. 
Ahora si podemos volver al cálculo del Slack:



Slack = requirement-(data path - clock path skew + uncertainty)





Slack = 10 - (4.207 + 0 + 0)  = 5.793 ns


A continuación del análisis de tiempo detallado arriba, TA presenta un análisis de los distintos componentes en el camino analizado. Debajo se puede ver el detalle, que luego se analiza. 


-------------------------------------------------------------------------------------------------------------
 Data Path: baud_gen/count_x16_13 to baud_gen/count_x16_4
    Delay type         Delay(ns)  Logical Resource(s)
    ----------------------------  -------------------
    Tcko                  0.374   baud_gen/count_x16_13
    net (fanout=2)        0.417   baud_gen/count_x16<13>
    Tilo                  0.288   baud_gen/count_x16_cmp_eq000062
    net (fanout=1)        0.920   baud_gen/count_x16_cmp_eq000062
    Tilo                  0.313   baud_gen/count_x16_cmp_eq000076
    net (fanout=18)       1.582   baud_gen/count_x16_cmp_eq0000
    Tilo                  0.313   baud_gen/Mcount_count_x16_eqn_41
    net (fanout=1)        0.000   baud_gen/Mcount_count_x16_eqn_4
    Tdyck                 0.000   baud_gen/count_x16_4
    ----------------------------  ---------------------------
    Total                 4.207ns (1.288ns logic, 2.919ns route)
                                  (30.6% logic, 69.4% route)
-------------------------------------------------------------

Data Path especifica el origen (baud_gen/count_x16_13) y el destino (baud_gen/count_x16_4)del camino analizado.
La primer columna es la Location (ubicación) del componente en el FPGA, por defecto esta off , por eso no se puede ver en listado de arriba, pero se puede activar activando Preference al hacer click con el botón derecho en un lugar en blanco de TA. La próxima columna es el Delay Type, si es una ruta, el fanout de la misma es mostrado. Los nombres detallados en esta columna corresponden con los detallados en la respectiva hoja de datos. Dentro de Timing Analyzer doble-click sobre cualquiera de estos nombres y se abrirá una figura que gráfica el retardo.
La columna del Delay detalla los respectivos retardos para cada Delay Type
La próxima columna son los nombres del Logical Resource. Los nombres detallados en esta columna son nombres generados durante el proceso de Map y se asocian a estos componentes. 
Al final del reporte se detalla la suma total del retardo para el camino analizado, 4.207 ns en este caso, seguido por un análisis de cuanto de ese total corresponde a retardo lógico y cuanto a retardo de ruteo. En este caso hay un 70% de retardo de ruteo  y un 30% de retardo lógico, valores bastantes lógicos J y que deberían ser estandars en diseños con FPGAs. 

Wow! q manera de escribir,.... espero q le sea útil a alguien.... :) 


Hasta pronto ! 

sábado, 28 de agosto de 2010

Warning: NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0

Este es un mensaje que dependiendo en que tiempo de la simulación ocurra puede ser grave o no.
Veamos...
Primero, normalmente este mensaje significa que la función to_integer recibe un 'metavalue' del vector que le pasa el número (vector) binario a convertir a entero. 'metavalue' significa otro valor que no es '1' ni '0', por ejemplo puede ser 'X', 'U'.
La función to_integer comúnmente se usa en contadores o para leer o escribir en memoria. Por ejemplo la lectura de un data de una memoria se puede describir del siguiente modo:


  data_from_mem <= data_mem(to_integer(unsigned(address));


Este mensaje de Warning es común durante la primer parte de la simulación, llamada inicialización. Durante este tiempo los valores 'X' tardan un cierto tiempo (dependiendo del caso, pero aproximadamente entre 10-15 ns) en propagarse y obtener un valor lógico '0' o '1' estable. Por lo que durante este tiempo le están llegando los 'X' a la función to_integer, que no sabe que hacer con ellos y lo avisa con el Warning.


Cuidado ! ... Sin embargo, si este Warning aparece después del periodo de inicialización, es decir todas las señales de3 sistema ya tienen un valor logico '0' o '1' estable, lo mas probable es que sea realmente un bug en el diseño . . . -> a encontrar el problema.... :)


Finalmente, si te molesta el Warning.... se puede desactivarlo y de este modo hacer que no aparezca el mensaje del problema encontrado durante la conversión de la función to_integer. Para ello el famoso archivo modelsim.ini tiene una variable llamada NumerisStdNoWarnings. Seteando esta variable en '1' hace que los Warning relacionados con funciones y procedimientos del paquete numeric_std sean obviados.
Por ejemplo la siguientes líneas puedes encontrarlas en el modelsim.ini:

; Turn off warnings from the IEEE numeric_std and numeric_bit packages.
; NumericStdNoWarnings = 1

El ';' significa un comentario. Entonces, como se puede ver, por defecto la variable para evitar los Warnings, NumeriStdWarnings, no está activada ('1'). Para deshabilitar los Warnings solo deberías borrar el ';' que antecede a la variable.
Otra vez Cuidado! . . . porque puede ser que desactives el mensaje de Warning, te olvides y en otro diseño que a lo mejor realmente tienes problemas puede que queden ocultos por haber desactivado los Warnings. Para estos casos otra opción es tener un modelsim.ini por proyecto, pero ese ya es otro tema...


Si quieres jugar con el archivo modelsim.ini lo puedes encontrar en los siguientes directorios:
Entorno ISE:
..\Modeltech_XE_Starter
Entorno Libero:
..\Libero_vx.x\Model
Entorno Diammond:
?? (alguien lo tiene? pasemelo pls...)
Entorno Quartus:
??

Hasta la próxima...

domingo, 15 de agosto de 2010

Imprimiendo mensajes con Assert/Report

A partir de VHDL'93 report se puede usar como una instrucción sola (sin assert) para imprimir objetos del tipo string. Así por ejemplo se puede reportar el comienzo de un test del siguiente modo:

report "--- Comienzo del Test ---";

Esto es similar, pero no equivalente, a escribir:

1 assert FALSE
2    report
 "--- Comienzo del Test ---";

En primer lugar report es una instrucción secuencial. Por lo que debería ser usada dentro de un proceso. Por defecto el nivel de severidad de report es NOTE. Por otro lado, assert puede ser una instrucción concurrente o secuencial. En el caso de ser usada como concurrente es equivalente a ser usada en un proceso con una instrucción wait al final del mismo (no lista sensitiva). Este proceso se ejecutará solo una vez durante el comienzo de la simulación y esperará indefinidamente en el wait. El nivel de severidad por defecto para assert es ERROR.
Los strings que se imprimen usando report se pueden leer en la ventana de transcript del simulador. Por ejemplo para ModelSim es la ventana que ocupa la parte inferior del simulador.
Ahora bien, tal como lo especifica el IEEE estandard 1076-1993, LRM §8.3, report solo puede imprimir objetos tipo STRING. Por lo que es muy util y bonito a la hora de imprimir mensajes, pero bastante 'inútil' para otro tipo de objetos. Por ejemplo para imprimir un std_logic_vector.
Recordemos que un 'string' de std_logic_vector (algunas veces llamado bit string) NO es lo mismo que un objeto tipo string. Por ejemplo: 

1 signal slv: std_logic_vector(7 downto 0) := "01010101";
2 signal str: std_logic_vector(7 downto 0) := "01010101";

Para estos dos objetos el compilador sabe que son diferentes tipos, pues fueron declarados diferentes, aun cuando ambos valores parecen similares. Cada uno de estos arreglos tienen diferente tipos de elementos. Tipo string es un arreglo de character, mientras std_logic_vector as un arrreglo de std_logic. Tal como se detalla en sus declaraciones:
 
1 type std_logic_vector is array (natural range <  >) of std_logic;
2 type string is array (positive range <  >) of character;

Ya que
report solo puede imprimir strings, para imprimir otro tipo de objeto es necesaria la conversión a string. El atributo pre-definido IMAGE (LRM §14.1) convierte cualquier tipo o sub-tipo escalar a string. Así:

1 report integer'image(cuenta);

Imprime el valor del entero cuenta. Mientras que:


1 report std_logic'image(flag);


imprimirá el valor de flag del tipo std_logic.


A veces se desea imprimir no solo el valor del objeto, sino tambien el nombre del mismo. Para ello se usa el operador concatenación & (ampersand):

1 process
2    begin
3      if (cuenta = max_cuenta) then -- max_cuenta = 16
4        report "El valor del contador es: " & integer'image(cuenta);
5      end if;
6      wait;
7 end process;

En el simulador se vería el siguiente mensaje:

1 # ** Note:  El valor del contador es: 16
2 #    Time: 20 ns  Iteration: 3  Instance: /tb_test

Tal como se ha explicado anteriormente 'image solo convierte tipo o sub-tipos escalares a tipo string. De modo que si por ejemplo se desea imprimir un objeto tipo std_logic_vector, o un array no es posible hacerlo usando el atributo 'image. En estos casos es necesario escribir una función que convierta por ejemplo de std_logic_vector a string. En realidad haciendo una búsqueda en google se pueden encontrar estas funciones de conversión. Por ejemplo usando una función conversión a string de std_logic_vector llamada slv2string, la instrucción report quedaría escrita de la siguiente forma:

1 report "El vector direccion de memoria es: " & slv2string(address);

Bueno, bueno.......


Esto es todo por hoy.... en realidad escribí mucho y no es lo mejor... :) , más aún siendo Domingo.... :( :)

viernes, 6 de agosto de 2010

Hay solución para el 'feo' text editor del ISE... menos mal :) ..!

A quién le gusta el editor de VHDL/Verilog que viene con el ISE? ? ?  Por suerte lo puedes cambiar y usar el editor de tu preferencia. En este link encontrarás como hacerlo, eso sí, fíjate bien cual línea de comando debes usar dependiendo del editor...


http://www.xilinx.com/support/answers/13713.htm

sábado, 31 de julio de 2010

Codificación de Máquinas de Estado (FSM) con Synplify y XST

FSM codificación con Synplify:
Cuando se desea una asignación de código de estados específica para la FSM, Synplify permite realizar la asignación usando la siguiente sintaxis:


1 type fsm_type is (idle, setup, txing, stop);
2 attribute syn_enum_encoding: string;
3 attribute syn_enum_encoding of fsm_type: type is "111 101 001 011";


Cuando se desee asignar una codificación tal como Gray, OneHot, Sequential or Binary, se debe usar la siguiente sintaxis:

1 type fsm_type is (idle, setup, txing, stop);
2 attribute syn_encoding: string;
3 signal curr_state, nxt_state: fsm_type;
4 attribute syn_encoding of curr_state: signal is "onehot";

Importante: para que efectivamente Synplify realice las asignaciones específicadas por el atributo syn_encoding o syn_enum_encoding, la opción FSM Compiler en la pantalla principal de Synplify debe estar sin marcar (not checked).
En caso de usar Tcl script, use el siguiente comando para no hacer uso del FSM Compiler::

set_options -symbolic_fsm_compiler 0


Implementacion Segura (Safe Implementation):
Por defecto Synplify generará FSM optimizadas por velocidad y área; sin embargo hay casos en los la prioridad de la FSM es que funcione correctamente ante cualquier circunstancia. En el modo Safe Implementation, Synplify agregará lógica de modo que si la FSM alguna vez cae en un estado invalido (estado no asignado), sera forzada al estado de reset; evitando así que la FSM se 'cuelgue' dejando de funcionar correctamente. Para habilitar esta característica se usa el mismo atributo syn_encoding pero agregándole la opción safe. Sintaxis: 

1 attribute syn_encoding of curr_state: signal is "safe,onehot";

FSM codificación con Xilinx XST:
Se puede usar la siguiente sintaxis para una asignación de código de estados específica:

1 type fsm_type is (idle, setup, txing, stop);
2 attribute enum_encoding: string;
3 attribute enum_encoding of fsm_type: type is "111 101 001 011";


Sin embargo  XST no tendrá en cuenta lo especificado en el atributo a menos que se active el modo FSM en modo 'user' (usuario). El modo FSM 'user' se puede seleccionar de dos modos, usando attribute o mediante Project Manager.
Usando attribute:

4 attribute fsm_encoding: string;
5 signal curr_state, nxt_state: fsm_type;
6 attribute fsm_encoding of curr_state: signal is "user";

GUI:
- Click el botón derecho del mouse sobre la opción Synthesize-XST
- Seleccione Properties
- Seleccione HDL Options
- Seleccione FSM Encoding Algorithm como User


El atributo fsm_encoding también se usa en el caso que se desee una asignación de estados con alguno de los siguientes valores:
- Auto
- OneHot
- Compact
- Sequential
- Gray
- Johnson
- Speed1
Para especificar una codificacion use la siguiente sintaxis:

1 type fsm_type is (idle, setup, txing, stop);
2 attribute fsm_encoding: string;
3 signal curr_state, nxt_state: fsm_type;
4 attribute fsm_encoding of curr_state: signal is "one-hot";

En caso de no especificar ninguna codificacion en particular Auto sera usado por XST por defecto.
Implementacion Segura (Safe Implementation):
En el modo Safe Implementation, XST genera lógica adicional que fuerza la FSM a un estado válido en caso que la FSM entre en un estado inválido. Sintaxis:
 1 type fsm_type is (idle, setup, txing, stop);
2 attribute safe_implementation: string;
3 signal curr_state, nxt_state: fsm_type;
4 attribute safe_implementacion of curr_state: signal is "yes";

viernes, 16 de julio de 2010

ieee.numeric_std.all vs. ieee.std_logic_arith.all;


Los siguientes paquetes
ieee.numeric_std.all / ieee.std_logic_arith.all / ieee.unsigned.all/ ieee.signed.all;
 nunca deberían usarse juntos.
ieee.numeric_std.all se refiere a un paquete de la librería estandard de la IEEE; la que debería ser usada para todos los diseños nuevos.
ieee.std_logic_arith.all,ieee.std_logic_unsigned.all, ieee.std_logic_signed.all se refieren a un paquete definido por Synposys algunos años atrás, y que por ser una de las herramientas de síntesis más usadas, estos paquetes eran usados casi por defecto.

Hasta el día de hoy Xilinx ISE usa los siguientes paquetes,  por defecto, cuando se usa la opción de crear un nuevo módulo VHDL:

 use ieee.std_logic_arith.all;
 use ieee.std_logic_unsigned.all;


A fin de que el código VHDL ha escribir sea 100% IEEE estandard, estos dos paquetes deben ser reemplazados por:

 use ieee.numeric_std.all;

Sin embargo, vale la pena aclarar lo siguiente: el paquete std_logic_arith es normalmente usado porque tiene definido operaciones matemáticas, como suma y resta, para el tipo std_logic, el std_logic_vector y el tipo integer. El paquete numeric_std  NO tiene definidas operaciones matemáticas para std_logic, std_logic_vector, pero sí las tiene definidas para los tipos signed,  unsigned e integer. Por ello para los casos en que sean necesarias operaciones matemáticas entre señales o variables, estas se deberán declarar como tipo signed, unsigned  o integer, y usar 'casting' o funciones de conversión para pasar de unsigned/signed/integer a std_logic_vector.
El ejemplo más típico es el de un contador descrito en VHDL. La forma correcta de describirlo sería la siguiente:

 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3 use ieee.numeric_std.all;
 4
 5 -- entity declaration
 6 entity counter_load is
 7    port (
 8         -- clock, reset ports
 9         clock     : in std_logic;
10         reset     : in std_logic;
11         -- control ports
12         load      : in std_logic;
13         -- input ports
14         initial_value   : in std_logic_vector(3 downto 0);
15         -- output ports
16         count   : out std_logic_vector(3 downto 0)
17  ) ;
18 end counter_load;
19
20 -- architecture declaration
21 architecture counter_load_beh of counter_load is
22  signal count_i: unsigned(3 downto 0);
23
24 -- architecture body
25 begin
26    count_proc: process(clock, reset)
27   begin
28     if(reset='0') then
29       count_i <= (others => '0');
30     elsif(rising_edge(clock)) then
31       if (load = '1') then
32         count_i <= unsigned(initial_value);
33       else
34         count_i <= count_i + 1;
35       end if;
36     end if;
37   end process count_proc;
38
39   count <= std_logic_vector(count_i);
40
41 end architecture counter_load_beh; 

En este ejemplo se puede ver el use de 'cast'. En linea 32 se usa el cast unsigned para asignar el standard_logic_vector initial_value al unsigned count_i. Mientras que en linea 39 se usa el cast std_logic_vector para asignar el unsigned count_i al standard_logic_vector count.

Otro ejemplo similar es el siguiente:

 1 library ieee;
 2 use ieee.std_logic_1164.all;
 3 use ieee.numeric_std.all;
 4
 5 -- entity declaration
 6 entity counter_ud is
 7    port (
 8         --  clocks, reset ports  
 9         clock     : in std_logic;
10         reset     : in std_logic;
11         --  control ports  
12         load   : in std_logic;
13         --  inputs ports  
14         initial_value: std_logic_vector(3 downto 0);
15         --  output ports
16         count   : out std_logic_vector(3 downto 0)
17         );
18 end counter_ud;
19
20 -- architecture declaration
21 architecture counter_ud_beh of counter_ud is
22   signal count_i: integer range 0 to 15;
23
24 -- architecture body
25 begin
26   count_proc: process(clock, reset)
27   begin
28     if(reset='0') then
29       count_i <= 0;
30     elsif(rising_edge(clock)) then
31       if(load = '1') then
32         count_i <= to_integer(unsigned(initial_value));
33       else
34         count_i <= count_i + 1;
35       end if;
36     end if;
37   count <= std_logic_vector(to_unsigned(count_i,4));
38   end process count_proc;
39
40 end architecture counter_ud_beh;

En este caso en línea 32 ocurre algo interesante: primero se usa el cast unsigned para convertir a unsigned el std_logic_vector initial_value. Luego se usa la función to_integer para convetir el unsigned a integer y asignárselo a count_i, que lógicamente es de tipo integer. En línea 37 ocurre algo similar, pero no igual :) : se usa la función to_unsigned para convertir el entero count_i que se puede representar con 4 bits (count_i es declarado de 0 a 15), y luego se usa el cast std_logic_vector para pasar de unsigned a std_logic_vector y así poder asignar el vector a count que es un std_logic_vector.

Dentro de poco pondré un cuadro que resume los cast y functions de conversiones ......
Espero que te sea de utilidad....
Nuevo!! : baja el pdf haciendo click aca  -> :)