![]() | arbeitet als Verification-Consultant bei Synopsys und ist Autor des Electronic-Design-Automation- Bestsellers SystemVerilog for Verification. Er hat für Kunden in Europa, Japan und den USA SystemVerilog- und Vera-Testbenches entwickelt. Bevor er zu Synopsys kam, entwickelte er bei Digital Equipment einen Hardware-Simulator und war dort auch für die Prozessor-Verifikation verantwortlich. |
Designs sind derart komplex, dass sogar die Kommunikation zwischen Blöcken in eine separate Einheit ausgelagert werden muss. Um diesen Sachverhalt zu modellieren, gibt es in SystemVerilog das Interface- Konstrukt, welches Anwender sich als ein intelligentes Bündel von Drähten vorstellen können. Es enthält die Konnektivität, Synchronisation und optional auch die Kommunikationsfunktionen zwischen zwei oder mehr Blöcken. Es verbindet Design-Blöcke und Testbenches. Der Bus-Control-Block wird durch Register gesteuert, die über einen einfachen Bus gelesen und beschrieben werden. In Verilog würde das DUT die zu Listing 3 zusammengefasste Portliste besitzen. (Die Tone-Signale sind nicht dargestellt.) Mit steigender Port-Anzahl kann es sehr leicht passieren, dass sich ein Verdrahtungsfehler einschleicht – beispielsweise die Verwechslung der Signale „rw_“ und „enb“. Dies lässt sich vermeiden, wenn man stattdessen diese Signale in einen Interface-Block verlagert und deren Richtwirkungen mit dem Konstrukt „modport“ spezifiziert (siehe Listing 4).
Beachtung finden sollte auch der in SystemVerilog neu definierte Datentyp „logic“. In diesem Zusammenhang muss man wissen, dass das klassische „reg“ in Verilog eine Variable deklariert, die für den RTL- und den Testbench- Code verwendbar ist, aber nicht Module oder Gatter verbinden kann. Die Bezeichnung „reg“ verleitete neue Anwender zu dem Glauben, dass es sich um ein Speicherelement handele – z.B. um ein Flipflop . In SystemVerilog indes sind „logic“ und „reg“ Benennungen für denselben Datentypen. Eine „logic“-Variable kann in RTLund Testbench-Code verwendet werden, außerdem ist sie in der Lage, Module und Gatter zu verbinden, solange es nur einen einzigen Treiber gibt. Ein Signal mit mehreren Treibern, beispielsweise ein bidirektionaler Bus, muss ein Netz wie „wire“ verwenden, um den resultierenden Wert zu ermitteln.
Im Sinne möglichst hoher Produktivität sollten Anwender ihre Testbenches auf einer hohen Abstraktionsebene erstellen. Selbst ein BFM sollte Signale synchron treiben und lesen, so dass die Testbench nicht fortlaufend wieder mit dem Takt in Einklang gebracht werden muss. Designer können das Timing ihrer Interface-Signale mittels eines Taktblocks (clocking block) spezifizieren (siehe Listing 5). Zu beachten ist dabei, wie die Richtungen im taktenden Block relativ zur Testbench definiert sind. Der Programmblock nutzt den Taktblock für die synchrone Kommunikation mit einem Interface. Das in Listing 6 beschriebene Beispiel schreibt einen Wert in Register 6600. Das Top-Level- Modul instanziiert das DUT, die Testbench sowie das Interface, welches DUT und Testbench verbindet. In dem Beispiel gemäß Listing 7 besagt das Kürzel „.*“ in der Portliste, dass die Ports anhand von Namensgleichheiten auf der aktuellen Ebene verbunden werden. Das Programm „test“ hat einen einzigen Port, „ifc“, der mit dem Port „ifc“ des Blocks „ucntrl_ifc“ verbunden ist.
Als Hardwarebeschreibungssprachen wie VHDL oder Verilog zum ersten Mal zum Einsatz kamen, wurde der RTL-Code durch Anlegen von Einsen und Nullen an das DUT getestet. Dies hat sich bald als derart langwierig herausgestellt, dass spezielle Routinen entwickelt wurden, welche immer wiederkehrende Aufgaben ausführen – beispielsweise das Senden einer Nachricht auf einen Bus.
Die VMM-Methodik erweitert diese fundamentale Idee, indem sie eine aus mehreren Schichten bestehende Testbench definiert und verwendet (siehe Bild 2). Die unterste Schicht ist die Signalschicht, welche „atomare“ Kommandos empfängt, das DUT ansteuert und die Ausgabe des DUT aufzeichnet. In dieser Schicht gibt es ferner Assertions, die die Signale des DUT und seiner Peripherie laufend überwachen, um sicherzustellen, dass sie dem zugehörigen Protokoll entsprechen. Im Bus-Control-System liest und beschreibt das Bus-Functional- Model (BFM) des Mikrocontrollers die jeweiligen Register im DUT. Die nächsthöhere Schicht ist die Kommandoschicht. Sie bricht High-Level-Kommandos herunter in kleinere Kommandos. Im Bus-Control-System wird eine Nachricht in Register-Lese- und Schreibzugriffe zerlegt. Die Kommandoschicht umfasst außerdem das Scoreboard, das die erwarteten Ausgaben des DUT enthält, sowie einen Checker zum Vergleich der erwarteten mit den tatsächlichen Ausgaben. Der Generator erzeugt einen Strom zufälliger Transaktionen (Nachrichten), welche den Transactor speisen.
Im Sinne maximaler Flexibilität sollte eine Testbench unter Verwendung von Objekten erstellt werden. Die Alternative ist, Module zu verwenden, aber diese können nicht dynamisch instanziiert werden. Außerdem ist eine Testbench in einem Modul anfällig für Race-Conditions, wie im nächsten Abschnitt erläutert wird. Die meisten der Blöcke in Bild 2 sind durch eine einfache Schleife modelliert, welche eine Transaktion vom jeweils vorhergehenden Block liest, eine grundlegende Transformation ausführt und sie dann zum nächsten Block sendet. Die Kommunikation zwischen Blöcken wird mit Hilfe eines VMMChannels bewerkstelligt. Dies ist ein FIFO, welches Transaktionen beinhaltet. In der Testbench des Bus-Control- Blocks erhält der Transactor Nachrichten vom Generator, zerlegt sie in individuelle Bytes und sendet sie zum Driver (siehe Listing 2). ?? Der „program“-Block enthält die Testbench In Verilog-Simulationen werden manchmal Race-Conditions verursacht, wenn die Testbench und das Design Signale gleichzeitig lesen und schreiben. SystemVerilog eliminiert dieses Problem durch Einführung des „program“-Blocks, welcher die Testbench enthält. Während eines Timeslots werden zuerst alle Design-Events ausgeführt, solche innerhalb von Modulen, und erst dann die vom Programm hervorgerufenen Events. Die Trennung der zwei Event-Typen stellt sicher, dass Testbench-Events nicht mit denen des Designs vermischt werden.