e es un lenguaje de verificación de hardware (HVL) que está diseñado para implementar bancos de pruebas de verificación altamente flexibles y reutilizables .
El software Specman fue desarrollado por primera vez en 1992 en Israel por Yoav Hollander . En 1995 fundó una empresa, InSpec (posteriormente rebautizada como Verisity), para comercializar el software. El producto se presentó en la Design Automation Conference de 1996. [1] Desde entonces, Verisity ha sido adquirida por Cadence Design Systems .
Las principales características de e son:
El lenguaje e utiliza un enfoque de programación orientada a aspectos (AOP), que es una extensión del enfoque de programación orientada a objetos para abordar específicamente las necesidades requeridas en la verificación funcional. AOP es una característica clave que permite a los usuarios agregar fácilmente funcionalidad adicional al código existente de una manera no invasiva. Esto permite una fácil reutilización y mantenimiento del código, lo que es un gran beneficio en el mundo del hardware, donde los diseños se modifican continuamente para satisfacer las demandas del mercado durante todo el ciclo de vida del proyecto. AOP también aborda cuestiones transversales (características que se extienden a través de varias secciones del código) fácilmente al permitir a los usuarios extender instancias específicas o todas las instancias de una estructura particular para agregar funcionalidad. Los usuarios pueden extender varias estructuras para agregar funcionalidad relacionada con una característica particular y agrupar las extensiones en un solo archivo si lo desean, lo que proporciona una partición de archivos más organizada.
El código ejecutable está encerrado entre los marcadores de segmento de código <' y ">:
Todo lo que esté fuera de los marcadores es un comentario.<'extender sys { // Este es un comentario estilo Verilog --Este es un comentario en estilo VHDL post_generate() también es { out("... y todo lo demás dentro de los marcadores es código ejecutable."); };};'>
e también tiene dos tipos de clases:
Una clase puede contener campos, métodos, puertos y restricciones. Los campos pueden ser de tipo entero, real, enumeración, cadena e incluso objetos complejos. El segmento de código muestra una unidad llamada 'environment_u' que se instancia dentro de la raíz 'sys'. Esta clase environment_u contiene una lista de 5 objetos packet_s y esta clase packet_s contiene dos campos y un método.
<'// Esta es una clase dinámica con dos camposestructura paquete_s { field0: uint (bits: 32); // Este campo se llama 'field0' y es un // Entero sin signo de 32 bits de ancho. campo1: byte; // Este campo se llama 'campo1' y es un byte. // Este método se llama una vez que se ha generado un objeto packet_s post_generate() también es { out(field0); // Imprimir el valor de 'field0' };};// Esta es una clase estática con una lista de cinco estructuras de paquetes.unidad entorno_u { my_pkt[5]: lista de paquetes;};// sys es la raíz de cada entorno e instancia el objeto 'test_env'extender sys { test_env: environment_u es instancia;};'>
En e, cada campo se aleatoriza de forma predeterminada. La aleatorización de campos se puede controlar mediante restricciones duras, restricciones suaves o incluso desactivarse por completo. Las restricciones suaves se utilizan como restricciones predeterminadas y la capa de prueba puede anularlas automáticamente si se produce un conflicto. De lo contrario, se comporta como una restricción normal.
<'estructura mi_paquete_s { destination_address: uint (bits: 48); // este campo es aleatorio y no está restringido. data_payload: lista de bytes; !parity_field : uint (bits: 32); // '!' evita que el campo de paridad se aleatorice. mantener suave data_payload.size() en [64..1500]; // una restricción suave, utilizada para proporcionar una aleatorización predeterminada Mantenga data_payload.size() no en [128..256]; // esta es una restricción estricta};'>
e admite aserciones con expresiones temporales. Una expresión temporal se utiliza en el mismo nivel sintáctico que los campos y métodos y, por lo tanto, es declarativa por naturaleza. Una expresión temporal describe un comportamiento cronometrado.
<'unidad temporal_ejemplo_u { evento a; // declarando un evento 'a' evento b; // declarando un evento 'b' evento c; // declarando un evento 'c' // Esta afirmación espera que el siguiente ciclo después del evento a //Se ha detectado que ocurre el evento b seguido del evento c. esperar @a => {@b;@c}};'>
Los grupos de soporte se agrupan según el evento muestreado y están estructurados internamente con elementos. Los elementos pueden ser elementos simples o elementos complejos, como elementos cruzados o elementos de transición.
ejemplo de cobertura de unidad u { evento cov_event_e; // la cobertura recopilada estará vinculada a este evento La cubierta cov_event_e es { elemento a: uint (bits: 4); // este elemento tiene 16 contenedores del 0 al 15 elemento b: bool; // este elemento tiene dos contenedores: VERDADERO y FALSO cruz a, b; // este elemento contiene una matriz de multiplicación cruzada de a y b trans b; // este elemento se deriva del elemento b y tiene cuatro contenedores // transición de cada combinación VERDADERO - FALSO };};
La mensajería dentro de correo electrónico se puede realizar con varios métodos.
unidad mensaje_ejemplo_u { ejemplo_metodo_mensaje() es { out("Este es un mensaje de salida incondicional y sin formato."); outf("Este es un mensaje de salida formateado incondicional que se muestra en HEX %x",15); imprimir "Este es un mensaje incondicional."; message(BAJO, "Este es un mensaje condicional, generalmente vinculado a un registrador de mensajes. ", "También puedes concatenar cadenas como esta e incluso agregar objetos como ",me, " en esta salida." ); messagef( LOW, "Esta salida condicional tiene el formato %x.",15 ); };};
Es probable que un banco de pruebas electrónico se ejecute con modelos RTL o de nivel superior. Teniendo esto en cuenta, e es capaz de interactuar con VHDL , Verilog , C , C++ y SystemVerilog .
// Este código está en un archivo Verilog tb_top.v módulo testbench_top ; reg a_clk ; siempre # 5 a_clk = ~ a_clk ; inicial comienzo a_clk = 0 ; fin finmódulo
Este código está en un archivo signal_map.e<'unidad señal_mapa_u { // Define un puerto llamado 'a_clk_p' a_clk_p: en simple_port de bit es instancia; // Establezca la propiedad hdl_path del puerto para que apunte a la señal 'a_clk' en el banco de pruebas de nivel superior mantener a_clk_p.hdl_path() == "~/testbench_top/a_clk";};'>
El proceso de verificación funcional requiere elevar el nivel de abstracción de cualquier Diseño Bajo Prueba (DUT) más allá del nivel RTL. Esta necesidad exige un lenguaje que sea capaz de encapsular datos y modelos, algo que está fácilmente disponible en lenguajes orientados a objetos. Para abordar esta necesidad, se ha diseñado e un lenguaje orientado a objetos y, además, se ha mejorado con mecanismos orientados a aspectos que facilitan no solo la escritura de bancos de pruebas altamente flexibles y reutilizables, sino que también ayudan a los ingenieros de verificación al permitirles corregir errores RTL descubiertos sin tener que reescribir o tocar nada de la base de código ya existente.
La programación orientada a aspectos en e permite a los ingenieros de verificación estructurar su banco de pruebas en aspectos. Por lo tanto, un objeto es la suma de todos sus aspectos, que pueden distribuirse en varios archivos. Las siguientes secciones ilustran los mecanismos básicos orientados a aspectos en e.
La subtipificación es el mejor ejemplo de lo que los lenguajes orientados a objetos sin características orientadas a aspectos no pueden lograr. La subtipificación permite a un ingeniero de verificación agregar funcionalidad a una clase ya definida/implementada sin tener que derivar de una clase base. El siguiente código muestra la implementación original de una clase base y cómo se extiende. Una vez que se realizó la extensión, todos los objetos de la clase base también contienen las extensiones. Las restricciones dadas en los dos subtipos diferentes generalmente causarían una contradicción, sin embargo, ambos subtipos se manejan por separado y, por lo tanto, cada subtipo produce un cálculo de restricción diferente.
ejemplo_de_subtipificación.e<'// Esta definición de tipo de enumeración se utiliza para declarar los subtipos ODD y EVENtipo ctrl_field_type_t: [IMPAR, PAR];unidad base_ex_u { // El campo_subtipo es el campo determinante cuyo cálculo se está aplicando campo_subtipo: campo_ctrl_tipo_t; palabra_datos : uint (bits: 32); paridad_bit : bit; // Subtipificación del tipo ODD cuando ODD'subtype_field base_ex_u { // Esta es una restricción simple que realiza una operación XOR del bit de índice 0 de data_word e incrementa ese valor mantener paridad_bit == (palabra_datos[0:0] ^ palabra_datos[0:0] + 1); }; // Subtipificación del tipo EVEN cuando EVEN'subtype_field base_ex_u { // Esta restricción es la misma que la anterior, sin embargo el incremento no se realiza mantener paridad_bit == (palabra_datos[0:0] ^ palabra_datos[0:0]); };};'>
La definición de la unidad original se encuentra en el archivo 1.e. El mecanismo orientado a aspectos utilizado en este ejemplo muestra cómo ejecutar código antes y después de un método ya implementado.
Este código está en el archivo 1.e<'unidad aop_ejemplo_u { meth_ext() es { out("Esta es la implementación del método original."); };};'>
Este código está en el archivo2.e<'extender aop_example_u { meth_ext() es primero { out("Esta extensión del método se ejecuta antes de la implementación del método original."); }; meth_ext() también es { out("Esta extensión del método se ejecuta después de la implementación del método original."); };};'>