VHDL-Testbenches mit externen Stimulus-Dateien über TEXTIO steuern
Das Einlesen von Stimulus-Daten aus einer externen Datei ist eine mächtige Methode, um ein Device-Under-Test (DUT) in VHDL zu steuern. Durch das Scripten einer Sequenz von Signalwerten und Simulationszeiten in einer Plain-Text-Datei können Designer Testmuster schnell austauschen, ohne die Testbench-Logik zu ändern. Dieser Artikel, der zweite in einer Serie über VHDL-Dateizugriff, demonstriert, wie man eine Stimulus-Datei mit der TEXTIO-Bibliothek einliest und ihre Werte auf einen 4-Eingang-Multiplexer anwendet.
Testfall-Übersicht
Das DUT ist ein standardmäßiger, asynchroner 4-zu-1-Multiplexer mit 8-Bit-Datenwörtern. Der Testbench führt keine Ausgangsverifikation durch – er treibt lediglich die Eingänge an, damit das Wellenform manuell untersucht werden kann. Die Entity-Deklaration wird unten zur Referenz wiedergegeben.
entity mux_4 is port( din_0 : in unsigned(7 downto 0); din_1 : in unsigned(7 downto 0); din_2 : in unsigned(7 downto 0); din_3 : in unsigned(7 downto 0); sel : in unsigned(1 downto 0); dout : out unsigned(7 downto 0)); end entity;
Signale, die mit dem DUT verbunden sind, werden in der Testbench-Architektur deklariert und mit dem Label DUT instanziiert:
signal din_0 : unsigned(7 downto 0); signal din_1 : unsigned(7 downto 0); signal din_2 : unsigned(7 downto 0); signal din_3 : unsigned(7 downto 0); signal sel : unsigned(1 downto 0); signal dout : unsigned(7 downto 0); DUT: entity work.mux_4(rtl) port map ( din_0 => din_0, din_1 => din_1, din_2 => din_2, din_3 => din_3, sel => sel, dout => dout );
Stimulus-Datei gestalten
Obwohl viele Formate möglich sind, illustriert das folgende Beispiel ein klares, menschenlesbares Layout. Jede Zeile repräsentiert einen Simulationsschritt und enthält:
- wait_time – Verzögerung vom vorherigen Schritt (z. B.
10 ns) - sel – 2-Bit-Selektorwert
- din_0 bis din_3 – 8-Bit-Datenwerte in hexadezimal
- Optionaler Trailing-Kommentar beginnend mit
#für Konsolenausgabe
Kommentare, die eine Zeile beginnen, werden vom Testbench ignoriert; Kommentare, die einem Datensatz folgen, werden auf der Simulator-Konsole ausgegeben.
# Spaltenbeschreibung: # wait_time | sel | din_0 | din_1 | din_2 | din_3 # Optionale Konsolenausgabe 0 ns 0 AA BB CC DD # Initiale Werte setzen 10 ns 1 AA BB CC DD # Test durch Ändern des Selektorsignals 10 ns 2 AA BB CC DD 10 ns 3 AA BB CC DD 10 ns 3 A1 B1 C1 D1 # Test durch Ändern aller Dateneingänge 10 ns 3 A2 B2 C2 D2 10 ns 3 A3 B3 C3 D3 10 ns 3 00 00 00 D2 # Alle nicht-selektierten Eingänge ändern 10 ns 3 01 02 03 D2 10 ns 3 11 22 33 D2 1 ns 0 CC DD EE FF # Alle Eingänge schnell ändern 1 ns 1 DD EE FF CC 1 ns 2 EE FF CC DD 1 ns 3 FF CC DD EE 10 ns 0 00 00 00 00 # Simulationsstopp
Datei mit TEXTIO einlesen
Unten steht der Kernprozess, der die Stimulus-Datei öffnet, jede Zeile parst, Werte den DUT-Eingängen zuweist und Kommentare behandelt. Das Beispiel geht von einer gut formatierten Datei aus – eine Leerstelle trennt Spalten, und das #-Zeichen wird von einem einzelnen Leerzeichen gefolgt.
PROC_SEQUENCER : process file text_file : text open read_mode is "stimulus.txt"; variable text_line : line; variable ok : boolean; variable char : character; variable wait_time : time; variable selector : sel'subtype; variable data : dout'subtype; begin while not endfile(text_file) loop readline(text_file, text_line); -- Leere Zeilen und Zeilenkommentare überspringen if text_line.all'length = 0 or text_line.all(1) = '#' then next; end if; read(text_line, wait_time, ok); assert ok report "Read 'wait_time' failed for line: " & text_line.all severity failure; hread(text_line, selector, ok); assert ok report "Read 'sel' failed for line: " & text_line.all severity failure; sel <= selector; hread(text_line, data, ok); assert ok report "Read 'din_0' failed for line: " & text_line.all severity failure; din_0 <= data; hread(text_line, data, ok); assert ok report "Read 'din_1' failed for line: " & text_line.all severity failure; din_1 <= data; hread(text_line, data, ok); assert ok report "Read 'din_2' failed for line: " & text_line.all severity failure; din_2 <= data; hread(text_line, data, ok); assert ok report "Read 'din_3' failed for line: " & text_line.all severity failure; din_3 <= data; wait for wait_time; -- Trailing-Kommentar auf Konsole ausgeben, falls vorhanden read(text_line, char, ok); -- Erwarteten Newline überspringen read(text_line, char, ok); if char = '#' then read(text_line, char, ok); -- Erwarteten Newline überspringen report text_line.all; end if; end loop; finish; end process;
Simulationsausgabe
Beim Ausführen in ModelSim zeigt die Konsole die Trailing-Kommentare zusammen mit der kumulierten Simulationszeit. Der folgende Ausschnitt zeigt die Sequenz der ausgegebenen Notizen:
# ** Note: Setting initial values # Time: 0 ns Iteration: 1 Instance: /file_stim_tb # ** Note: Testing by changing the selector signal # Time: 10 ns Iteration: 0 Instance: /file_stim_tb # ** Note: Testing by changing all data inputs # Time: 40 ns Iteration: 0 Instance: /file_stim_tb # ** Note: Changing all unselected inputs # Time: 70 ns Iteration: 0 Instance: /file_stim_tb # ** Note: Changing all inputs fast # Time: 91 ns Iteration: 0 Instance: /file_stim_tbf # ** Note: Simulation stop # Time: 104 ns Iteration: 0 Instance: /file_stim_tb # Break in Process PROC_SEQUENCER at file_stim_tb.vhd line 98
Das vom Testbench erzeugte Wellenform spiegelt Timing und Datenwerte aus der Datei wider und ermöglicht Designern, das DUT-Verhalten visuell zu verifizieren.
Wesentliche Erkenntnisse
- Externe Stimulus-Dateien geben Designern feinkörnige Kontrolle über Testsequenzen ohne Testbench-Code-Änderung.
TEXTIOhält den Testbench prägnant, erfordert aber disziplinierte Dateiformatierung.- Immer einen Selbstprüfmechanismus einbauen – entweder durch Vergleich mit einem Verhaltensmodell oder durch Einbetten erwarteter Ausgaben in die Stimulus-Datei.
Indem Sie dem obigen Beispiel folgen, können Sie die volle Flexibilität von VHDLs TEXTIO nutzen, um komplexe Testszenarien zu steuern, während Sie eine saubere, wartbare Testbench-Struktur beibehalten.

VHDL
- C# using-Anweisungen meistern: Importe, Aliase und statische Direktiven
- C-Dateiverwaltung: I/O mit fopen, fprintf, fread & fseek meistern
- Java-Dateioperationen mit java.io meistern – Erstellen, Lesen, Schreiben & Löschen
- FPGA Block RAM aus Textdateien mit VHDLs TEXTIO-Bibliothek initialisieren
- Selbstprüfenden VHDL-Testbench erstellen – Praxisleitfaden
- Dateien in Java mit BufferedReader lesen – Praktischer Leitfaden mit Beispielen
- Python JSON: Encoding, Decoding und Datei-Handling – Ein praktischer Leitfaden
- Datei-E/A in Verilog meistern: Öffnen, Lesen, Schreiben und Schließen
- C-Header-Dateien verstehen: Typen, Verwendung und Best Practices
- Dreikantfeile: Aufbau, Anwendung und Pflege