e (Bestätigungssprache) - e (verification language)

e
Paradigma Aspektorientiert
Entworfen von Yoav Hollander
Erstmals erschienen 1992 ( 1992 )
Stabile Version
IEEE 1647-2016 / 6. Januar 2017 ; vor 4 Jahren ( 2017-01-06 )
Dateinamenerweiterungen .e
Webseite TWiki @ eda.org


e ist eine Hardware-Verifikationssprache (HVL), die auf die Implementierung hochflexibler und wiederverwendbarer Verifikations- Testbenches zugeschnitten ist .

Geschichte

e wurde erstmals 1992 in Israel von Yoav Hollander für seine Specman- Software entwickelt. 1995 gründete er ein Unternehmen, InSpec (später umbenannt in Verisity ), um die Software zu kommerzialisieren. Das Produkt wurde auf der Design Automation Conference 1996 vorgestellt . Verisity wurde inzwischen von Cadence Design Systems übernommen .

Merkmale

Hauptmerkmale von e sind:

  • Zufällige und eingeschränkte zufällige Reizgenerierung
  • Definition und Erfassung von Metriken zur funktionalen Abdeckung
  • Zeitliche Sprache, die zum Schreiben von Behauptungen verwendet werden kann
  • Aspektorientierte Programmiersprache mit Reflexionsfähigkeit
  • Die Sprache ist DUT-neutral, da Sie eine einzelne e- Testbench verwenden können, um ein SystemC/C++-Modell, ein RTL-Modell, ein Gate-Level-Modell oder sogar ein DUT, das sich in einer Hardware-Beschleunigungsbox befindet (mit der UVM-Beschleunigung für e- Methodik) zu verifizieren.
  • Kann hochgradig wiederverwendbaren Code erstellen, insbesondere wenn die Testbench nach der Universal Verification Methodology (UVM) geschrieben wurde
    • Früher bekannt als e Re-use Methodology ( e RM)
    • UVM e Bibliothek und Dokumentation können hier heruntergeladen werden: UVM World

Sprachmerkmale

Die e- Sprache verwendet einen aspektorientierten Programmieransatz (AOP), der eine Erweiterung des objektorientierten Programmieransatzes ist , um speziell die bei der funktionalen Verifikation erforderlichen Anforderungen zu erfüllen. AOP ist eine Schlüsselfunktion, die es Benutzern ermöglicht, auf einfache Weise zusätzliche Funktionen auf nicht-invasive Weise in vorhandenen Code zu integrieren. Dies ermöglicht eine einfache Wiederverwendung und Codepflege, was in der Hardwarewelt ein großer Vorteil ist, wo Designs während des gesamten Projektlebenszyklus ständig an die Marktanforderungen angepasst werden. AOP adressiert auch Cross-Cutting-Probleme (Features, die sich über verschiedene Abschnitte des Codes erstrecken), indem es Benutzern ermöglicht, entweder bestimmte oder alle Instanzen einer bestimmten Struktur zu erweitern, um Funktionen hinzuzufügen. Benutzer können mehrere Strukturen erweitern, um Funktionen für eine bestimmte Funktion hinzuzufügen, und die Erweiterungen bei Bedarf in einer einzigen Datei bündeln, um eine besser organisierte Dateipartitionierung zu ermöglichen.

Kommentare

Ausführbarer e- Code ist in Codesegment-Markierungen <' und '> eingeschlossen:

Beispiel

Anything outside the markers is a comment
<'
extend sys {
  // This is a comment Verilog style
  -- This is a comment in VHDL style
  post_generate() is also {
    out("... and everything else within the markers is executable code.");
  };
};
'>

Klassen

e hat auch zwei Arten von Klassen:

  • Dynamische Klassen sind mit dem Schlüsselwort 'struct' gekennzeichnet. Structs werden verwendet, um Daten zu erzeugen, die nur temporär existieren und vom Garbage Collector bereinigt werden können.
  • Statische Klassen sind mit dem Schlüsselwort 'unit' gekennzeichnet. Units werden zum Erstellen der permanenten Testbench-Struktur verwendet.

Eine Klasse kann Felder, Methoden, Ports und Einschränkungen enthalten. Felder können vom Typ Integer, Real, Enum, String und sogar komplexe Objekte sein. Das Codesegment zeigt eine Unit namens 'environment_u', die innerhalb der e-Root 'sys' instanziiert wird. Diese Umgebung_u-Klasse enthält eine Liste von 5 Paket_s-Objekten und diese Paket_s-Klasse enthält zwei Felder und eine Methode.

Beispiel

<'
// This is a dynamic class with two fields
struct packet_s {
  field0: uint (bits: 32);   // This field is called 'field0' and is a 
                            // 32 bit wide unsigned integer.
  field1: byte;             // This field is called 'field1' and is a byte.
  
  // This method is called once a packet_s object has been generated
  post_generate() is also { 
    out(field0);            // Printing the value of 'field0'
  };
};

// This is a static class with a list of five packet struct
unit environment_u {
  my_pkt[5]: list of packet_s;
};

// sys is the root for every e environment and instantiates the 'test_env' object
extend sys {
  test_env: environment_u is instance;
};
'>

Randomisierung

In e ist jedes Feld standardmäßig randomisiert. Die Feldrandomisierung kann durch harte Beschränkungen, weiche Beschränkungen gesteuert oder sogar vollständig ausgeschaltet werden. Soft Constraints werden als Standard-Constraints verwendet und können automatisch von der Testschicht überschrieben werden, wenn ein Konflikt auftritt. Ansonsten verhält es sich wie ein regulärer Constraint.

Beispiel

<'
struct my_pkt_s {
  destination_address: uint (bits: 48);   // this field is randomized and is not constrained.
  data_payload       : list of byte;     
  !parity_field      : uint (bits: 32);   // '!' prevents the parity_field from being randomized.
  
  keep soft data_payload.size() in [64..1500];  // a soft constraint, used to provide a default randomization
  keep data_payload.size() not in [128..256];   // this is a hard constraint
};
'>

Behauptungen

e unterstützt Assertionen mit temporalen Ausdrücken. Ein zeitlicher Ausdruck wird auf der gleichen syntaktischen Ebene wie Felder und Methoden verwendet und ist daher von Natur aus deklarativ. Ein zeitlicher Ausdruck beschreibt zeitgesteuertes Verhalten.

Beispiel

<'
unit temporal_example_u {
  event a;   // declaring an event 'a'
  event b;   // declaring an event 'b'
  event c;   // declaring an event 'c'
  
  // This assertion expects that the next cycle after event a
  // has been detected that event b followed by event c occurs.
  expect @a => {@b;@c}
};
'>

Abdeckung

e unterstützt Abdeckungen, die nach ihrem Stichprobenereignis gruppiert sind, und diese Gruppen sind intern mit Elementen strukturiert. Elemente können einfache Elemente oder komplexe Elemente wie gekreuzte Elemente oder Übergangselemente sein.

Beispiel

unit coverage_example_u {
  event cov_event_e;   // collecting coverage will be tied to this event

  cover cov_event_e is {
    item  a: uint (bits: 4);   // this item has 16 buckets from 0 to 15
    item  b: bool;            // this item has two buckets: TRUE and FALSE
    cross a, b;               // this item contains a cross multiplication matrix of a and b
    trans b;                  // this item is derived of item b and has four buckets
                              // transitioning each TRUE - FALSE combination
  };
};

Nachrichten und Berichte

Die Nachrichtenübermittlung innerhalb von e kann mit verschiedenen Methoden erfolgen.

Beispiel

unit message_example_u {
  example_message_method() is {
    out("This is an unconditional, unformatted output message.");
    outf("This is an unconditional, formatted output message displaying in HEX %x",15);
    print "This is an unconditional message.";
    message( LOW, "This is a conditional message, usually tied to a message logger. ",
                  "You can also concatenate strings like this and even add objects like ",me,
                  " in this output." );
    messagef( LOW, "This conditional output is formatted %x.",15 );
  };
};

Schnittstellen zu anderen Sprachen

Ein e- Testbench wird wahrscheinlich mit RTL- oder höherwertigen Modellen betrieben. Vor diesem Hintergrund ist e in der Lage, mit VHDL , Verilog , C , C++ und SystemVerilog zu kommunizieren .

Beispiel für einen e <-> Verilog-Anschluss

// This code is in a Verilog file tb_top.v
module testbench_top;
  reg a_clk;   
  always #5 a_clk = ~a_clk;
  initial begin
    a_clk = 0;
  end
endmodule
This code is in a signal_map.e file
<'
unit signal_map_u {
  // Define a port named 'a_clk_p'
  a_clk_p: in simple_port of bit is instance;
  // Set the port's hdl_path property to point to the 'a_clk' signal in the top-level testbench
  keep a_clk_p.hdl_path() == "~/testbench_top/a_clk";
};
'>

Aspektorientierte Programmierunterstützung in e

Der Prozess der funktionalen Verifizierung erfordert, dass die Abstraktionsebene jedes Design Under Test (DUT) über die RTL-Ebene hinaus angehoben wird. Diese Notwendigkeit erfordert eine Sprache, die Daten und Modelle kapseln kann und die in objektorientierten Sprachen leicht verfügbar ist. Um diesen Bedarf wurde entwickelt, um E eine objektorientierte Sprache und obendrein wurde mit aspektorientierte Mechanismen ergänzt , die erleichtern nicht nur sehr flexibel und wiederverwendbar Testbenches schreiben, sondern hilft auch Verifikationsingenieure von zu Patch ermöglicht entdeckt RTL Fehler, ohne die bereits vorhandene Codebasis neu schreiben oder berühren zu müssen.
Die aspektorientierte Programmierung in e ermöglicht es Verifikationsingenieuren, ihre Testbench in Aspekten zu strukturieren. Ein Objekt ist also die Summe all seiner Aspekte, die auf mehrere Dateien verteilt sein können. Die folgenden Abschnitte veranschaulichen grundlegende aspektorientierte Mechanismen in z.

Subtyping-Mechanismus

Subtyping ist das Paradebeispiel dafür, was objektorientierte Sprachen ohne aspektorientierte Funktionen nicht erreichen können. Subtyping ermöglicht es einem Verifikationsingenieur, einer bereits definierten/implementierten Klasse Funktionalität hinzuzufügen, ohne von einer Basisklasse ableiten zu müssen. Der folgende Code zeigt die ursprüngliche Implementierung einer Basisklasse und wie sie erweitert wird. Sobald die Erweiterung stattgefunden hat, enthalten alle Basisklassenobjekte auch die Erweiterungen. Die in den beiden verschiedenen Subtypen angegebenen Beschränkungen würden normalerweise zu einem Widerspruch führen, jedoch werden beide Subtypen separat behandelt und somit führt jeder Subtyp zu einer anderen Beschränkungsberechnung.

Beispiel für einen Subtyping-Mechanismus

subtyping_example.e
<'
// This enum type definition is used to declare the subtypes ODD and EVEN
type ctrl_field_type_t: [ODD, EVEN];
unit base_ex_u {
  // The subtype_field is the determinant field which calculation is being applied
  subtype_field: ctrl_field_type_t;
  data_word    : uint (bits: 32);
  parity_bit   : bit;
  
  // Subtyping the ODD type
  when ODD'subtype_field base_ex_u {
    // This is a simple constraint that XORs the index bit 0 of data_word and increments that value
    keep parity_bit == (data_word[0:0] ^ data_word[0:0] + 1);
  };

  // Subtyping the EVEN type
  when EVEN'subtype_field base_ex_u {
    // This constraint is the same as above, however the increment is not done
    keep parity_bit == (data_word[0:0] ^ data_word[0:0]);
  };
};
'>

Erweiterungsmethoden

Die ursprüngliche Einheitendefinition ist in file1.e angegeben. Der in diesem Beispiel verwendete aspektorientierte Mechanismus zeigt, wie Code vor und nach einer bereits implementierten Methode ausgeführt wird.

Beispiel für eine Methodenerweiterung

This code is in file1.e
<'
unit aop_example_u {
  meth_ext() is {
    out("This is the original method implementation.");
  };
};
'>
This code is in file2.e
<'
extend aop_example_u {
  meth_ext() is first {
    out("This method extension is executed before the original method implementation.");
  };

  meth_ext() is also {
    out("This method extension is executed after the original method implementation.");
  };
};
'>

Verweise

  1. ^ Samir Palnitkar: Design-Verifizierung mit e , Prentice Hall PTR. 5. Oktober 2003. ISBN  978-0-13-141309-2

Quellen