miércoles, 21 de agosto de 2013

Como 'ver' los 'delta delay' en ModelSim

Introducción 

Para algunas personas el concepto de delta delay en HDLs es uno de los mas difíciles de 'digerir' (entender). No es el objetivo de este articulo escribir acerca del concepto de 'delta delay' y sus derivados .... (hay demasiada literatura al respecto), lo que SI quiero hacerles llegar es que ModelSim tiene herramientas disponibles de modo que de manera sencilla se puede 'ver' el delta delay en forma gráfica o tabular. 

Como 'ver' los delta delays en ModelSim

Explicaré los pocos pasos necesarios a seguir para saber y ver cuantos delta times suceden hasta que una señal obtiene un valor estable. 
Primero, les detallo el simple código VHDL a usar para la demostración.

 1 library ieee;
 2 use eee.std_logic_1164.all;
 3
 4 entity aoi is
 5 port(A, B, C, D: in std_logic;
 6      E         : out std_logic);
 7 end aoi;
 8
 9 architecture beha4 of aoi is
10 signal O1, O2, O3:std_logic;
11
12 begin
13 b4: process(A, B, C, D, O1, O2, O3)
14  begin
15   E  <= not O3;
16   O1 <= A and B;  
17   O2 <= C and D;  
18   O3 <= O1 or O2;
19 end process b4;
20 end dflow1;

A continuación el simple test bench usado. 

 1 library ieee;
 2 use eee.std_logic_1164.all;
 3
 4 entity aoi_tb is
 5 end aoi_tb;
 6
 7 architecture test of aoi_tb is
 8 signal O1, O2, O3   : std_logic;
 9 signal a, b, c, d, e: std_logic;
10 component  aoi is
11   port(A, B, C, D: in std_logic; E: out std_logic);
12 end component;
13
14 begin
15    a <= '0', '1' after 6 ns;
16    b <= '0', '1' after 5 ns, '0' after 8 ns;
17    c <= '0', '1' after 7 ns;
18    d <= '0';
19
20 uut: aoi  port map(
21   E => e, a => a ,b => b ,c => c, d => d
22   );
23 end test;
24

Bien, entonces una vez que ejecutas el test bench en el entorno ModelSim se abre la ventana 'Wave', que muestra la forma de ondas de las senales del modulo que se esta simulando. Un punto a considerar es que normalmente por defecto se muestran solo por puertos de Entrada y Salida del modulo, por lo que hará falta agregar las señales internas necesarias a la ventana 'Wave' para poder ver los delta delay respectivos. 
Despues de ejecutar el test bench del ejemplo descrito la ventana Wave que se obtiene es la siguiente



Entonces, supongamos que queremos saber los delta delay asociados al evento en la senal 'B' al tiempo 8 ns. Los pasos a seguir son los siguientes: 
1- Colocar (sumar) un cursor en el tiempo de simulacion 8 ns. 
2- Hace click en el boton "Expanded Time Delta Mode"



3- Hace click en el boton "Expand Time At Active Cursor"



4- Click en "Zoom In At Active Cursor"




5- LiStO !

La siguiente figure resume los pasos detallados arriba  y muestra el resultado obtenido. 


< br/> Otro modo de Ver los Delta Delay

ModelSim ofrece tambien una especie de tabla, llamada en realidad 'List', donde detalla las senales, sus eventos y los respectivos delta delays. Para acceder a la misma hacer 'View->List'. De ese modo se obtiene una table similar a la siguiente.




Finalmente

Si alguna vez tuviste problemas para entender los delta delay, y como realmente 'funcionan', esta herramienta te ayuda mucho a poder dilucidad ese dilema... 

Hasta la próxima.....

martes, 4 de junio de 2013

Conversión ASCII a Hex

Introducción

Presentaré en esta entrada un modo fácil de convertir un texto en ASCII a Hex para ya sea para grabar el dato en memoria, transmitirlo a través de algún protocolo de comunicación, mostrarlo un dato en un LCD, etc.

Procedimiento

VHDL tiene definidas diversas funciones de conversiones de tipo en sus librerías estándar. Usaré algunas de ellas para esta conversión. 
Los pasos para la conversión son los siguientes:

1- declaración del string, constantes y señales (signals) de contador en la parte declarativa de la arquitectura: 

 1 architecture beh of test is
 2 .......
 3 constant N : natural := 16;
 4 type tstring is array(natural range<>) of character;
 5 constant msje1 : tstring(0 to N-1) := "Vuelvo en 5 ... ";
 6 .......
 7 -- declaracion de la senal para asignar el Hex correspondiente
 8 signal byte_to_Tx: std_logic_vector(7 downto 0);
 9
10 -- declaracion de contador
11 signal char_cont: natural range 0 to N-1;
12 .......

2- Uso de funciones de conversión para obtener el byte en Hex correspondiente a cada character del string: 

byte_to_tx<=std_logic_vector(to_unsigned(character'pos(msje1(char_cont)),8));

Analicemos esta instrucción parte por parte:
a-
msje1(char_cont);

lo que hace esta parte de la instrucción es posicionarse en un carácter especifico del mensaje 1. La posición esta dada por el valor del contador char_cont. Por supuesto que este instrucción debe estar dentro del lazo donde se incrementa el contador una vez enviado el respectivo caracter. 
b-
character'pos('character')

en esta parte representa el caracter del msje1 especificado por  char_cnt.  Por otro lado character'pos('V') (coloco 'V' como ejemplo de un caracter del msje1), lo que hace es primero devolver en valor numero la posición de 'V' en el arreglo character definido en el estandar de VHDL. Para refrescar un poco algo que seguramente alguna vez lo vieron, detallo a continuación el tipo character: 

 1 type character is (
 2     NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL,
 3     BS, HT, LF, VT, FF, CR, SO, SI,
 4     DEL, DC1, DC2, DC3, DC4, NAK, SYN, ETB,
 5     CAN, EM, SUB, ESC, FSP, GSP, RSP, USP,
 6     ‘ ’,’!’, “”,’#’,’$’,’%’,&,’’’,
 7     ‘(,),*, ‘+, ‘,,-,.,/,
 8     ‘0,1,2,3,4,5,6,7,
 9     ’8,9,:,;,<,=,>,’?’,
10     ‘@’,’A’,’B’,’C’,’D’,’E’,’F’,’G’,
11     ‘H’,’’I’,’J’,’K’,’L’,’M’,’N’,’O’,
12     ‘P’,’Q’,’R’,’S’,’T’,’U’,’V’,’W’,
13     ‘X’,’Y’,’Z’,’[‘,\,’]’,’^’,’_’,
14     ‘`’,’a’,’b’,’c’,’d’,’e’,’f’,’g’,
15     ‘h’,’i’,’j’,’k’,’l’,’m’,’n’,’o’,
16     ‘p’,’q’,’r’,’s’,’t’,’u’,’v’,’w’,
17     ‘x’,’y’,’z’,’{‘,|,’}’,’~’,DEL);
18

así, el caracter 'V' se posiciona en el lugar 86 dentro del arreglo, por lo que el character'pos('V') devuelve el numero 86 (como entero). 
c- Entonces ahora tenemos que convertir el 86 entero a std_logic_vector. Usando la ya 'famosa' tablita de funciones de conversión sabemos que debemos pasar primero el entero a unsigned y luego a std_logic_vector. Eso es realizado por la siguiente parte de la instrucción:  

std_logic_vector(to_unsigned(86,8));

donde 8 es la cantidad de bits necesarios para representar el máximo número estimado a convertir (en este caso 256). 
d-Finalmente el binario correspondiente al caracter especificado por char_cont es asignado a la señal byte_to_Tx


Final...

Espero que les sea útil... y si alguna vez la usan AVISEN.... 

Hasta pronto....









martes, 14 de mayo de 2013

ModelSim-Quartus: "Failed to find INSTANCE '/NA'"

Introducción

Como bien es sabido los mensajes de error dados por la herramientas que comúnmente usamos son bastantes encriptados, y por ende no fácil de darnos cuenta cual es el origen del mismo. Uno de estos casos es este mensaje generado por ModelSim cuando tratamos de ejecutar una 'gate level simulation", ya sea automáticamente desde Quartus o desde el mismo ModelSim:



Veremos en esta entrada del blog como se soluciona este error. 


Descripción


La simulación a nivel de compuertas, gate level simulation (también conocida como post-place and route simulation) es un paso importante para asegurarnos que el sistema implementado en el FPGA cumple satisfactoriamente los requerimientos de tiempo después de colocar (place) y rutear (route) la logica de nuestro sistema en el FPGA. Para ejecutar la simulación a nivel de compuertas, es necesario generar un archivo de simulación (netlist) con todos los retardos (logics y de ruteo) y simular el sistema con ese archivo (netlist).
Quartus tiene una manera de configurar la simulación a ejecutar de un modo bastante detallado. Para la simulación a nivel RTL el procedimiento fue explicado en este blog anteriormente.  
Para ejecutar la simulación a nivel de compuerta (gate level simulation) Quartus genera a partir del .vhd a simular y de la información provista por la herramienta de place & route (especialmente con los retardos, delays, incorporados) un archivo con extensión .sdo, (standard delay output,  usualmente llamado standard delay format, .sdf), que contiene toda la información de los delays lógicos y de ruteo, y un archivo .vho, que contiene toda la información del conexionado del sistema a implementar en el FPGA. Ambos archivos contienen todo lo necesario para llevar a cabo la simulación a nivel de compuerta. Para los que les interese pueden abrir los archivos generados en el directorio: 

.../tu_proyecto/simulation/modelsim/nombre_top_entity_.vho
.../tu_proyecto/simulation/modelsim/nombre_top_entity_.sdo

Pasos a Seguir

Si has intentado correr la simulación a nivel de compuertas es porque ya tienes el respectivo test bench escrito. Solo falta decirle a Quartus por medio de lo Altera llama NativeLink que el dispositivo bajo test esta identificado con el nombre de la instancia en el test becnh. 
Para configurar el proceso de correr automáticamente en ModelSim la simulación a nivel de compuertas llevá a cabo los siguientes pasos. 
1- Ir a Assignments -> Settings
2- La ventana de 'Settings' se abrirá. Seleccioná 'Simulation'.
3- Dentro de la ventana de 'Simulation', hace click en el cuadrado de 'Run gate-level simulation automatically after compilation'. 
La siguiente figura muestra los pasos 2 y 3. 



4- En la misma ventana 'Simulation', y en la parte inferior done dice 'Compile test bench', simple click en 'Test Bench'. 
5- La ventana 'Test Benches' se abrirá. Simple click en 'Edit'.



6- Ahora deberá aparecer la ventana titulada 'Edit Test Bench Settings'; mostrando el nombre del test bench que será usado en la simulación. En esta ventana seleccione 'Use test bench to perform VHDL timing simulation'. Y en la parte donde dice 'Design instance name in test bench' debes escribir el nombre de la instancia del componente en el test bench. Por ejemplo en el test bench tengo la siguiente instrucción de instanciación de componente: 



En el caso que estoy detallando, yo use U1 como nombre de la instancia. 
Hay que ser muy cuidadoso de verificar cual es el nombre de la instancia y escribirlo en "Design instance name in test bench". 


7- Click Ok. y cerrar cualquier otra ventana que haya quedado abierta. 
8- Ya puedes efectuar una simulación a nivel de compuertas usando


Nota 1: por favor acordate después de ejecutar una simulación a nivel de compuertas de borrar el archivo vsim.wlf generado por ModelSim, porque es inmensamente grande.
Nota 2: agradezco la inquietud de mis alumnos Mario Ruiz, y Germán González en este post. 
Nota 3: como podrán ver en el calendario me borre por unos meses.... bueno.. anduve haciendo otros trabajos no tan lindos como codificar en VHDL e implementar en FPGA..... así es q estoy muy contento de poder volver a mi temática favorita!!

jueves, 7 de febrero de 2013

Operadores de Reducción Lógica - Operadores 'Unarios'

Introducción

En versiones anteriores de VHDL, los operadores lógicos and, or, nand, nor, xor and xnor eran definidos solo como operadores boleanos, es decir, se necesitaban dos operandos para realizar la respectiva función lógica boleana. Para casos en que los operandos eran arreglos y se necesitaba un simple valor escalar como resultado, se escribía un loop para aplicar el operando lógico a los elementos del arreglo.
VHDL-2008 extiende la definición de operandos lógicos para permitir que sean usados como operadores 'UNARIOS' (unary operands). Veremos a continuación cuales son los operandos unarios definidos en VHDL-2008 y como se usan. 

Repaso Operadores Booleanos

De acuerdo a la defincion del estandard de VHDL hay tres difrentes familias de operadores booleanos. Estos operadores estan definidos para tipo bit y boolean, y sus derivados, como asi tambien para los arreglos de estos tipos. 

1- Operador booleanos básico: realizan la operación lógica booleana entre cada bit de los operandos (bitwise logic), y produce como resultado un arreglo del mismo tamaño que los operandos. 


2- Operador booleano selectivo (operador unario): realiza la operación lógica booleana entre un simple bit y cada elemento del operando. El resultado es del mismo tamaño que el del operando. 


3- Operador booleano reducido: definido en VHDL-2008. Realiza la operación lógica booleana entre todos los elementos del arreglo, produciendo como resultado un simple bit. 


Cuáles son y Cómo se usan: Operadores Unarios

Los operadores unarios se usan específicamente en arreglos, y se aplican a cada elemento del arreglo para producir un escalar como resultado (en realidad también se pueden aplicar a arreglos de un elemento, pero en realidad no tiene mucho sentido). 
A continuación algunos ejemplos de uso y resultado de operadores unarios: 

and"0110" = '0' and '1' and '1' and '0' = '0'
or "0110" = '0' or  '1' or  '1' or  '0' = '1'
xor"0110" = '0' xor '1' xor '1' xor '0' = '0'

Los operandos de reducción nand, nor, xnor, son la negación de los operandos and, or y xor respectivamente. Por lo que: 

nand"0110" = not ( '0' and '1' and '1' and '0') = not '0' = '1'
nor "0110" = not ( '0' or  '1' or  '1' or  '0') = not '1' = '0'
nxor"0110" = not ( '0' xor '1' xor '1' xor '0') = not '0' = '1'

Los operandos de reducción tienen la misma precedencia que el operador unario not. En caso de ausencia de paréntesis estos operadores son evaluados antes de los operadores binarios. Así por ejemplo esta expresión

and Z xor B

Se evalúa primero el operando de reducción and, es decir la operación and Z, y luego se aplica el operador binario xor entre el resultado de la operación and Z y B.

Un caso típico de ventaja de uso del operador unario es por ejemplo en calculo de paridad de un vector. En versiones anteriores el código era escrito mas o menos de la siguiente forma:

parity <= data(7) xor data(6) xor data(5) xor data(4) xor
          data(3) xor data(2) xor data(1) xor data(0);

Usando el operador unario, se puede escribir sencillamente como:

parity <= xor data;

sábado, 2 de febrero de 2013

Especificando el 'timescale' en Verilog

Introduccion

después de algunos pedidos, empezaré también a escribir blogs con respecto al otro HDL, Verilog. En este caso en particular detallo el uso de la directiva de compilación (compiler directive) "timescale". 

Detalles

La directiva 'timescale' especifica la unidad de tiempo y precisión ha ser usada por la herramienta de simulación. 
La sintaxis es la siguiente: 

'timescale time_units / precision_units

Donde "time_units" es un valor que declara la unidad de tiempo de los retardos en el módulo en el que se especifica este valor. Mientras que "precision_units" es un valor que declara la precisión de la unidad de tiempo ha ser usada por el simulador cuando simule el módulo en el que se especifica este valor. Como regla práctica trate de usar como valor de la precisión un valor cercano al valor de la unidad de tiempo. Ambos valores deben ser números enteros (1, 10, 100), y son seguidos por un string que representa la unidad de tiempo (s, ms, us, ns, ps, fs). 

Reglas: 


  • se deben usar valores de 1, 10, 100 para la unidad de tiempo y para la precisión.
  • puede usar 's' para segundos, 'ms' para milisegundos, 'us' para microsegundos, 'ns' para nanosegundos, 'ps' para picosegundos y 'fs' para fentosegundos, para ambos, la unidad de tiempo y la de precisión.
  • la unidad de tiempo debe ser por lo menos tan grande como la unidad de precisión
  • no existe un valor de 'timescale' por defecto; pero los simuladores pueden asignar uno por defecto.
  • para mantener consistencia de los valores de 'timescale', se debe usar una directiva de timescale para TODOS los módulos del diseño.

Esta directiva se escribe fuera de la definición del módulo.

IMPORTANTE: Se debe tener cuidado de que no exista una gran diferencia entre el valor de la unidad de tiempo y el valor de la unidad de precisión  ya el tiempo de simulacion avanza en incrementos de la unidad de precisión. Así  por ejemplo, si escribimos

`timescale 1ns/100ps

el simulador hará 10 pasos para avanzar 1 ns de tiempo de simulación. Si, escribimos

`timescale 1ns/1ps

el simulador hará 1000 pasos para avanzar 1 ns de tiempo de simulación. 
Otro ejemplo: 

`timescale 1ns/10ps
module1 (. . .);
  not #1.23 (. . .) // 1.23ns (12300 simulation time units)
  . . .
endmodule


Use valores de precisión que no sobrecarguen la tarea del simulador. Valores demasiados pequeños  incrementarán sin sentido el tiempo de simulación y el uso de memoria. Un valor práctico es el siguiente: 

`timescale 1ns/1ns


En caso de proyectos con múltiples módulos  el valor de 'timescale' es pasado a todos los módulos que no tienen definido el 'timescale' y que son sub-módulos del mismo. El simulador usualmente da un 'warning' para los módulos que no tienen definido el valor (los valores de 'timescale').

Finalmente un figura es mejor que mil palabras....




Primer blog de Verilog..... !!! pero, por supuesto no el último :) !!