Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> VHDL

Fichier de stimulation lu dans testbench à l'aide de TEXTIO

La lecture des valeurs de signal à partir du fichier est un autre moyen de générer des stimuli pour l'appareil testé (DUT). La séquence et la synchronisation du testbench sont codées en dur dans un fichier de stimulus qui est lu par le testbench VHDL, ligne par ligne. Cela vous permet de modifier facilement le modèle de la forme d'onde que vous souhaitez envoyer à l'objet de test.

Parfois, vous avez un modèle de test très spécifique ou une séquence d'événements que vous souhaitez soumettre à votre DUT. Vous pouvez y parvenir en spécifiant dans un fichier ASCII les valeurs de signal que chaque signal doit avoir, ainsi que le temps de simulation relatif sur lequel ils doivent changer. Le rôle du testbench VHDL dans une telle stratégie est de lire les données du fichier de stimulus et d'appliquer les valeurs aux entrées du DUT au bon moment.

Cet article est le deuxième d'une série sur l'accès aux fichiers en VHDL. Nous avons examiné comment lire des valeurs hexadécimales, octales et binaires à partir d'un fichier dans le précédent article de blog, revenez en arrière et lisez-le si vous voulez en savoir plus sur la lecture à partir d'un fichier à l'aide du TEXTIO bibliothèque en VHDL.

Ce billet de blog fait partie d'une série sur l'utilisation de la bibliothèque TEXTIO en VHDL. Lisez les autres articles ici :

Comment initialiser la RAM à partir d'un fichier à l'aide de TEXTIO

Image bitmap de fichier BMP lue à l'aide de TEXTIO

Le cas de test

L'exemple DUT sera un multiplexeur à 4 entrées (MUX) tiré de l'un de mes précédents articles de blog. Il s'agit d'un multiplexeur 4 vers 1 asynchrone standard avec une largeur de données d'un octet. Comment cela fonctionne n'est pas important pour cet article car nous n'allons pas vérifier les sorties, c'est juste à des fins de démonstration.

L'entité du MUX est indiquée ci-dessous.

entity mux_4 is
  port(
    -- Data in
    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);

    -- Selector
    sel  : in unsigned(1 downto 0);

    -- Data out
    dout : out unsigned(7 downto 0));
end entity;

Après avoir importé les packages nécessaires en haut du fichier VHDL, nous déclarons les signaux d'entrée que nous allons connecter au DUT. Comme vous pouvez le voir dans la liste ci-dessous, ce sont des plans de la déclaration d'entité MUX.

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);

Nous utilisons la méthode d'instanciation d'entité pour créer une instance du MUX avec l'étiquette "DUT" en haut de la région d'architecture de notre testbench. Les signaux d'entité sont connectés aux signaux de testbench locaux avec les mêmes noms, comme indiqué dans le code ci-dessous.

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
);

Le fichier de relance

Un fichier de relance peut avoir de nombreux formats différents, celui présenté ici n'est qu'un exemple que j'ai trouvé du haut de ma tête en écrivant cet article. Néanmoins, lorsque vous comprendrez comment je l'ai créé, vous devriez pouvoir le modifier en fonction de vos besoins.

La liste ci-dessous montre le fichier de stimulus complet utilisé dans cet exemple.

# Column description:
# wait_time | sel | din_0 | din_1 | din_2 | din3 # Optional console printout

0 ns 0 AA BB CC DD # Setting initial values
10 ns 1 AA BB CC DD # Testing by changing the selector signal
10 ns 2 AA BB CC DD
10 ns 3 AA BB CC DD
10 ns 3 A1 B1 C1 D1 # Testing by changing all data inputs
10 ns 3 A2 B2 C2 D2
10 ns 3 A3 B3 C3 D3
10 ns 3 00 00 00 D2 # Changing all unselected inputs
10 ns 3 01 02 03 D2
10 ns 3 11 22 33 D2
1 ns 0 CC DD EE FF # Changing all inputs fast
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 # Simulation stop

Ignorons les commentaires pour l'instant, ce sont ceux marqués en vert, commençant toujours par un caractère "#". Chaque ligne représente un pas de temps dans la simulation. Il y a six colonnes de commandes sur chaque ligne, en fait sept colonnes de texte, mais les deux premières colonnes appartiennent au même élément de données.

Les colonnes de texte un et deux décrivent une valeur de temps, pendant combien de temps le simulateur doit s'arrêter sur cette ligne avant d'appliquer les valeurs répertoriées dans les autres colonnes. Ainsi, le temps de simulation absolu lors de l'exécution de la commande est relatif à l'événement décrit par la ligne précédente. Nous n'utilisons que 0, 1 ou 10 nanosecondes, mais cela peut être n'importe quoi, 1000 nanosecondes ou 1000 heures (1000 hr ) d'ailleurs.

Les cinq colonnes de texte restantes décrivent les valeurs de signal à appliquer aux entrées du DUT. Ils sont donnés sous forme de littéraux hexadécimaux et l'ordre des signaux est sel , din_0 , din_1 , din_2 , et enfin din_3 .

Passons maintenant aux commentaires. Il existe deux types de commentaires ; commentaires sur une seule ligne et commentaires de fin. Ils seront traités différemment par notre banc d'essai. Les commentaires sur une seule ligne, comme ceux en haut du fichier, seront ignorés. Les commentaires de fin, en revanche, doivent être imprimés sur la console du simulateur. Nous pouvons les utiliser pour nous donner des indices sur ce qui se passe pendant l'exécution de la simulation.

Lecture du fichier de relance en VHDL

VHDL n'est pas le meilleur langage pour le traitement de texte, mais il fait le travail. La prise en charge des chaînes dynamiques est limitée et il manque des routines pratiques, par exemple pour supprimer ou ignorer les espaces. Pour nous faciliter la tâche, nous allons supposer que le fichier de relance est bien écrit. Veillons à ce qu'il y ait toujours un espace entre les éléments de texte et un seul espace entre le caractère "#" et le texte du commentaire. De plus, aucun espace supplémentaire de début ou de fin n'importe où dans le fichier de stimulus.

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

La région déclarative du PROC_SEQUENCER la procédure est indiquée ci-dessus. Tout d'abord, nous déclarons le file spécial objet, un type de gestionnaire de fichiers VHDL. Ensuite, on déclare une variable de type line . Il s'agit simplement d'un type d'accès à une chaîne, un pointeur vers un objet chaîne alloué dynamiquement. Le ok variable de type booléen sert à vérifier que les opérations de lecture ont réussi. Enfin, nous déclarons les quatre variables char , wait_time , selector , et data . Ces variables servent à extraire les données de chaque colonne de chaque ligne de texte.

  while not endfile(text_file) loop

    readline(text_file, text_line);

    -- Skip empty lines and single-line comments
    if text_line.all'length = 0 or text_line.all(1) = '#' then
      next;
    end if;

Dans le corps du processus, nous entrons directement dans une boucle while qui parcourt chaque ligne de texte du fichier de stimulus. Le readline procédure affecte une nouvelle ligne de texte au text_line variable à chaque itération de cette boucle. Après avoir lu la ligne, nous vérifions si la ligne est vide ou si le premier caractère est '#', auquel cas nous passons immédiatement à la ligne suivante en utilisant le next mot-clé pour ignorer une itération de la boucle. Notez que nous utilisons text_line.all pour accéder à la chaîne à l'intérieur du line objet.

    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;

Vient ensuite un certain nombre de lectures à partir du text_line objet. Le read et hread les appels de procédure ignorent les espaces de début afin que nous n'ayons pas à faire de lectures factices pour déplacer la position de début de lecture interne à l'intérieur du text_line objet. Nous aurions pu omettre les instructions assert, mais je veux que la simulation s'arrête si une lecture échoue. Au moins dans ModelSim, la simulation ne s'arrête pas automatiquement lorsque cela se produit. Nous attribuons chaque variable lue avec succès au signal DUT pertinent, à l'exception du wait_time variable qui n'a pas d'entrée DUT correspondante.

    wait for wait_time;

Après avoir attribué les valeurs de signal, nous attendons le temps spécifié. Si vous appuyez sur l'instruction d'attente, les valeurs de signal planifiées deviennent effectives avec le même cycle delta.

    -- Print trailing comment to console, if any
    read(text_line, char, ok); -- Skip expected newline
    read(text_line, char, ok);
    if char = '#' then
      read(text_line, char, ok); -- Skip expected newline
      report text_line.all;
    end if;

  end loop;

  finish;

end process;

Enfin, lorsque le programme sort de l'instruction d'attente, nous recherchons un commentaire de fin supplémentaire sur le text_line objet. Tout commentaire est imprimé sur la console à l'aide de l'instruction report après avoir supprimé le caractère "#" et l'espace blanc suivant à l'aide de lectures factices.

Une fois que la dernière ligne de texte du fichier de stimulus a été traitée, la boucle while se termine. Il y a un VHDL-2008 finish mot-clé à la fin du processus qui est responsable de l'arrêt du banc de test.

La sortie

L'exemple de testbench imprime le texte ci-dessous sur la console du simulateur lorsqu'il est exécuté dans ModelSim. On voit que les commentaires sont ceux du dossier de relance. Les valeurs de temps imprimées sont les temps de simulation cumulés basés sur les retards en nanosecondes qui ont été spécifiés dans le fichier de stimulus.


# ** 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

La forme d'onde de la simulation est illustrée ci-dessous. Il montre une représentation visuelle de la façon dont les valeurs de notre fichier de stimulus sont appliquées aux signaux aux moments de simulation spécifiés.

Réflexions finales

La lecture de stimuli de testbench à partir d'un fichier peut être avantageuse si vous avez un modèle de test très spécifique que vous devez appliquer. L'ensemble du testbench n'a pas à être contrôlé par le fichier texte, cet exemple est juste destiné à montrer les possibilités d'accès aux fichiers en VHDL.

Cependant, une chose dont nous n'avons pas discuté est la vérification des sorties du DUT. Notre exemple de testbench ne vérifie pas du tout les sorties. Vous pouvez vérifier le comportement du DUT comme vous le feriez dans un banc d'essai VHDL complet, par exemple en utilisant un modèle comportemental à comparer. Ou vous pouvez modifier le code et le fichier de stimulus pour inclure les valeurs de sortie attendues. Quelle que soit la stratégie que vous choisissez, assurez-vous de créer un banc d'essai d'auto-vérification et ne comptez pas sur la vérification manuelle de la forme d'onde.


VHDL

  1. C# en utilisant
  2. Gestion des fichiers C
  3. Classe de fichier Java
  4. Comment initialiser la RAM à partir d'un fichier à l'aide de TEXTIO
  5. Comment créer un banc d'essai d'auto-vérification
  6. Java BufferedReader :comment lire un fichier en Java avec un exemple
  7. Python JSON :encoder (dumps), décoder (chargers) et lire le fichier JSON
  8. Opérations Verilog File IO
  9. C - Fichiers d'en-tête