Mostrando entradas con la etiqueta simulación. Mostrar todas las entradas
Mostrando entradas con la etiqueta simulación. 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, 26 de septiembre de 2018

Como añadir variables en el Waveform window de ModelSim

Necesitas debug el valor de alguna variable? ModelSim te da la opción de poder añadir una o más variables al Waveform window. 
Sin embargo es dificil encontrar info de como 'ver' una variable. Dentro de Modelsim hay que hacer una serie de pasos para poder agregar una variable el Waveform window:
  • Cargá la simulación de tu diseño en ModelSim siguiendo el proceso que usualmente haces (ya sea desde ISE, ModelSim stand-alone, Quartus, etc.)
  • En caso que aún no esté abierto, abre el Waveform window: del menú principal selecciona View y luego Wave.
  • En el Worksapce window de ModelSim seleccioná (highlight) el dispositivo que se quiere simular (DUT en este ejemplo).


  • Tal como se vé en la figura anterior en ModelSim en la Objects window NO se muestran las variables. 
  • Para habilitar la visualización de las variables, primero se debe habilitar la visualización de los procesos del proyecto general. Para eso, sobre el dispositivo a simular, DUT en este ejemplo, presioná botón derecho, y seleccioná Show, y luego Process



  • Ahora debajo del nombre del componente que se quiere simular (DUT en este ejemplo) deberán aparecer varios otros nombres/números. Entre ellos en nombre del proceso en el cual está definida la variable que se quiere agregar al Waveform window.  Por eso la IMPORTANCIA de poner nombre a los procesos.
  • Tal como se aprecia en la figura, el proceso que nos interesa se llama pwm_pr.  Este nombre viene del .vhd.
  • Próximo paso es seleccionar View en el menú principal y luego Locals. Ya que las variables son locales al proceso, es decir no existen fuera del proceso.
  • Luego seleccioná el nombre del proceso (highlight), pwm_pr en este caso, y entonces deberá aparecer una nueva ventana donde se mostrará el nombre del proceso, y debajo las variables definidas en el.
  • Seleccioná la variable (counter en este ejemplo) y luego Add Wave para que aparezca en el Waveform window. 
  • Grabá la nueva configuración del Waveform window, así la próxima vez que corras la simulación la(s) variable(s) estarán disponibles. Si trabajás con Quartus usá esta nota técnica C7T_AN08_Customized_WaveView_ModelSim_Quartus. Si trabajas con ISE usá esta C7T_AN05_Customized_WaveView_ModelSim_ISE_2.
  • domingo, 6 de septiembre de 2015

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

    Cuando se invoca cualquier tipo de simulación desde el ISE, ModelSim es automáticamente abierto. Una de las ventanas que se abre es la Wave View. Por defecto solo las señales de la entidad top son mostradas, y ... nada más... Entonces, si se desean ver señales internas, cambiar la posición y/o color de las señales, agregar divisores, y tantas otras características que ofrece ModelSim, se puede hacer, pero . . . solo temporariamente hasta cerrar ModelSim. Cuando se corra la misma simulación de nuevo, se deberá empezar otra vez con las modificaciones.
    En esta Application Note se detallan los pasos a seguir, para que cuando se invoque ModelSim desde el ISE, la simulación, y específicamente, el Wave View contenga toda la información que uno desea/necesita para una buena verificación o un fácil debug:


    C7T AN-05



    Happy design !

    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, 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!!

    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 !!!  :) 

    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.


    jueves, 5 de abril de 2012

    Modelacion Funcional de Bus (Bus Functional Model)


    Introducción

    BFM es una sigla muy usada en el ámbito de diseño de HDL-FPGA, sin embargo no todos saben que es ni a que se refiere, otros diseñadores se dedican a escribir BFMs por lo que saben muy bien lo que es. Bueno, este blog es para los que pertenecen al grupo que dice “Qué es eso?” cuando escucha ‘BFM’.

    Básicamente como su nombre lo indica, BFM es un modelo de simulación simplificado que describe correctamente la funcionalidad de I/O bus de un sistema normalmente complejo, sin inmiscuirse con el comportamiento interno de ese componente.

    Este modelo se usa dentro del test bench como estimulo (stimulus) del sistema que se quiere testear (DUT), permitiendo en forma directa una comunicación entre el DUT y el sistema externo con el que se quiere interactuar, evitando de esta manera tener que escribir un muy complejo test bench. La siguiente figura muestra el sistema de simulación cuando se usa un BFM.


    Figura 1 – Esquema de simulación usando BFM

    Explico ahora los distintos componentes en la Figura 1:
    Test Code: es el código del test bench en sí, escrito en VHDL. En este parte del test bench se escribe el código VHDL para estimular el DUT, principalmente haciendo uso de los procedimientos que modelan algún ciclo de I/O del componente BFM instanciado en el test bench. 
    BFM: es el código BFM del sistema que interactúa con el DUT. Este código es provisto por el fabricante del sistema/memoria o escrito por alguno de nosotros. Dentro del test bench se crea una declaración de este componente y su respectiva instanciación. Actúa como generación de estimulo para el DUT al proveer un preciso estimulo del protocolo de comunicación, ciclo por ciclo en funcionalidad y tiempo. Al mismo tiempo el BFM acepta comandos para seleccionar la funcionalidad a ser modelada. Estos comandos son normalmente asignados a alguna señal en el test bench, declarada en el  paquete, y ejecutados por el procedimiento respectivo del BFM. Este bloque básicamente se codifica como una simple maquina de estados, cuyos estados por ejemplo pueden ser read, write, idle. Y de acuerdo a lo que el test code ‘solicita’ la máquina de estados pasa al respectivo estado y activa las I/O necesarias del sistema modelado (BFM).
    DUT: es el device under test que queremos depurar.
    Package: es la unidad de diseño que contiene todas las declaraciones y descripciones de las señales, funciones, procedimientos relacionadas al test bench y al BFM. Actúa como medio de comunicación entre las señales del test bench y los procedimientos/funciones del BFM.
    El símbolo * lo uso para detallar que el código de test y el BFM ‘pueden’ (no es siempre el caso) proveer no solo el estimulo al DUT, sino también chequear la respuesta del DUT a cierto estimulo. Esta funcionalidad es opcional, sin embargo es altamente aconsejada para automatizar el test y proveer un rápido resultado del comportamiento del DUT bajo determinado estimulo.

    Quién escribe un BFM?

    Normalmente para componentes complejos, por ejemplo memorias DDR, Flash, dispositivos PCI, PCIe, etc; el fabricante ofrece un modelo BFM para que el diseñador pueda verificar que el protocolo que ha diseñado interactúa correctamente con el componente con el que quiere comunicarse.
    Ahora, bien el BFM, es en sí un modelo escrito en VHDL por un ingeniero de la empresa fabricante, por lo que el modela será tan bueno como el ingeniero que lo escriba.
    Debo aclarar que hay algunas empresas que escriben sus propios BFMs a fin de facilitar la simulación de componentes, normalmente varios, que tienen protocolos de comunicación complejos. En algunas de estas empresas tuve la oportunidad de escribir y usar algunos BFModels, tarea que al principio era linda, pero luego se transformó en tediosa… :) 

    Porqué usar BFM?

    El proceso de prueba (simulación) a veces es una tarea compleja que involucra muchas horas de escritura del código (test bench) y otras más de correr la simulación. Normalmente más de la mitad del tiempo de un proyecto involucra la simulación del mismo, y más se incrementa este tiempo cuando la complejidad del proyecto crece. Por ello es necesario usar métodos de prueba (test) más eficientes y que sigan asegurando un diseño libre de errores.
    El uso de BFM habilita el test de complejos protocolos y funciones con un gran nivel de abstracción de la funcionalidad interna del componente simulado, menos instrucciones a simular, preciso timing de la interface, todo lo que resulta en un test más robusto, completo y sobre todo más rápido de ejecutar. Esta última es una característica que se destaca cuando se comparan los tiempos de simulación de sistemas complejos, IP cores, etc., que usualmente toman un largo tiempo en simular.

    Características de un BFM

    • Provee un medio para modelar la interface del componente que se está modelando, SIN importar la estructura interna del componente o si el componente en si tiene un microprocesador, una o varias FSMs, etc.
    • Provee información de todos los tiempos del protocolo de comunicación de I/Os.
    • Provee chequeo funcional para verificar el correcto funcionamiento del protocolo (handshaking).
    • Normalmente son escritas usando las instrucciones típicamente usadas en Test Bench. Paquetes, funciones, procedimientos, registros y tipos son comúnmente encontradas en BFMs.
    • El alto nivel de abstracción que VHDL ofrece permite modelar complejos sistemas, en funcionalidad y tiempo, abstrayendo al diseñador de la complejidad interna del sistema modelado. 

    Ejemplo Flujo de Uso de BFM

    La siguiente figura detalla el procedimiento que se debería seguir cuando se usa un BFM.

     
    Figura 2 - Pasos a seguir para usar los procedimientos del BFM

    Paso 1: Dependiendo de la funcionalidad del BFM que se desea invocar, en el código del test bench se genera un llamado al procedimiento respectivo asignando los valores necesarios. Por ejemplo para comenzar un ciclo de escritura (Wr), habrá que asignar a la senal respectiva un ‘valor’ que entienda el procedimiento que se desea invocar.
    Paso 2: El procedimiento invocado seguramente necesita generar algún dato o señal antes de invocar al procedimiento principal.
    Paso 3: El procedimiento principal primero solicita la disponibilidad del bus de I/O, normalmente por medio de alguna señal de pedido (request) de bus. En caso que el bus no este disponible, por ejemplo porque todavía se está ejecutando algún otro procedimiento, deberá esperar hasta que el bus esté disponible.
    Paso 4: Las I/O del BFM son controladas por el procedimiento principal con el comportamiento deseado (Wr/Rd, etc.) y con el respectivo timing. Una vez finalizado el ciclo, el procedimiento avisa por medio de la misma senal de ocupado (busy)  desacertándola. Permitiendo así el recomienzo del ciclo.

    Escritura de BFMs

    Uno de los principales usos de BFMs es por ejemplo para representar ciclos de Wr/Rd del bus del componente que se desea modelar. Estos ciclos normalmente se describen mediante el uso de funciones y procedimientos definidos en un paquete para permitir la accesibilidad no solo del BFM pero también del test bench y del código VHDL  en sí.
    Los ciclos de Wr/Rd son fácilmente descriptos mediante el uso de procedimientos (procedures) que modelan perfectamente el comportamiento de los ciclos de Wr/Rd ya sea sobre memoria o sobre I/O, no solo funcionalmente sino también con los tiempos respectivos. La BFM debe ser capaz de leer un comando, por ejemplo, y devolver la respuesta a ese comando, de ese modo se prueba tanto la escritura como la lectura de mi componente sobre el componente modelado con BFM. Al usar procedimientos y ser un modelo de un sistema toda la potencia del lenguaje VHDL puede ser usada al escribir el BFM.
    La entidad/arquitectura del BFM debe ser instanciada junto con nuestro componente (DUT) dentro del test bench. Mínima configuración del BFM a veces es necesaria al comienzo del TB, hasta que pueda comenzar el handshaking entre mi componente y el componente BFM.
    Ejemplo del código escrito para una BFM.
    Declaraciones en el paquete:

     1 -- declaraciones de type y señales --    
     2 type cycle_op is (idle, nop, read, write);
     3
     4 type instruction_op is record
     5    bus_cycle   : cycle_op;
     6    addr_bus    : std_logic_vector(15 downto 0);
     7    data_bus    : std_logic_vector(15 downto 0);
     8    rd_data     : std_logic_vector(15 downto 0);
     9    bus_request : std_logic;
    10    busy        : std_logic;
    11 end record;
    12
    13 signal cmd     : instruction_op :=  (idle,
    14                                     (others => '0'),
    15                                     (others => '0'),
    16                                     (others => 'Z'),
    17                                     '0',
    18                                     'Z');
     
    En este ejemplo el registro (record) declara las señales a ser usadas para generar el estímulo de las I/O, como así también información a pasar al procedimiento que debe ejecutar el ciclo seleccionado. Es decir se declara:
    • Tipo del ciclo (idle, nop, read, write)
    • Dirección a ser utilizada en el bus de direcciones
    • Dato a ser escrito si es un ciclo de escritura, o dato que se espera leer si es un ciclo de lectura
    • Data leído
    • Señal de pedido de bus (bus_request). Se activa para solicitar comienzo de un ciclo.
    • Señal de bus ocupado (busy). Se activa durante el proceso de ejecución de algún ciclo. 
    Un procedimiento de un ciclo de escritura puede ser escrito tal como se detalla a continuación:

    1 -- declaracion del procedimiento wr_cycle
    2 procedure wr_cycle (
    3    constant p_addr_bus : in std_logic_vector(15 downto 0);
    4    constant p_data_bus : in std_logic_vector(15 downto 0);
    5    signal   p_cmd_op   : inout instruction_op
    6    ) is
    7 begin
    8     main_cycle(write,p_addr_bus, p_data_bus,p_cmd_op);
    9 end wr_cycle;

     

    Donde el procedimiento main_cycle es el siguiente:

     1 -- declaracion procedimiento main_cycle
     2 procedure main_cycle(
     3    constant p_cycle    : in cycle_op;
     4    constant p_addr_bus : in std_logic_vector(15 downto 0);
     5    constant p_data_bus : in std_logic_vector(15 downto 0);
     6    signal   p_cmd_op   : inout instruction_op
     7    ) is
     8 begin
     9   p_cmd_op.request <= '0';
    10   if p_cmd_op.busy /= '0' then
    11       wait on p_cmd_op.busy until p_cmd_op.busy = '0';
    12   end if;
    13   p_cmd_op.request   <= '1';
    14   p_cmd_op.bus_cycle <= p_cycle;
    15   p_cmd_op.addr      <= p_addr;
    16   p_cmd_op.data      <= p_data;
    17   if (p_cmd_op.busy = '0') then
    18      wait on p_cmd_op.busy until p_cmd_op.busy = '1';
    19   end if;
    20   p_cmd_op.request    <= '0';
    21 end;

    Este procedimiento lleva a cabo las tareas de ‘handshaking’, usando las señales busy y request, y de comunicación entre el test code y el BFM.
    Ahora, como invoco las distintas funciones del BFM dentro del test bench? La siguiente línea de código, escrita en el test bench, muestra como se puede invocar el procedimiento del ciclo de escritura:  

    1 wr_cycle(x"0000",x"05ab",cmd_op);

    Entonces lo que pasa es lo siguiente:
    • El procedimiento wr_cycle esta declarado en un paquete (ver figura 1)
    • El procedimiento wr_cycle le pasa los parámetros necesarios al procedimiento main_cycle
    • El procedimiento main_cycle lleva a cabo el handshaking, y pasa el comando (cmd_op) a la máquina de estados (FSM, Finite State Machine) de la BFM.
    • Al ser un comando de escritura la máquina de estado pasa al estado escritura donde procederá a activar las señales correspondientes del ciclo de escritura, y habilitar las de espera que el proceso se cumpla (ready). Este último paso es el que realmente ‘ve’ el DUT.
    La siguiente figura detalla la modificación de la primer figura al ejecutarse un ciclo de escritura, mostrando gráficamente los pasos recién enumerados.


    Figura 3 - Detalle de los procedimientos y código ejecutados durante un ciclo de escritura del BFM

    Unos puntos a considerar de la Figura 3:
    • La línea punteada entre el bloque Test Code y Package se debe a que en realidad el procedimiento wr_cycle está definido en el paquete pero, como bien sabemos, cuando se compila el código de Test Code, el procedimiento definido en el paquete es ‘insertado’ en el lugar en que éste es invocado
    • Lo mismo sucede con el procedimiento main_cycle. El cual es también ejecutado desde Test Code
    • Tal como se puede deducir del código de los procedimientos detallados anteriormente (wr_cycle, main_cycle), la señal cmd_op, definida como un registro, contiene toda la información necesaria para que la FSM del componente BFM genere el correspondiente ciclo de escritura en las líneas de I/O de este bloque (recordar que el componente BFM está instanciado dentro del test bench).

    Espero que este artículo sirva para, por lo menos, tener una idea de la pregunta: Qué es un BFM?