mikrocontroller.net

Forum: FPGA, VHDL & Co. Wie Testbench schreiben


Autor: ope (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

wie schreibt man am besten seinen Testbench? Ich bin langsam am
verzweifeln. Den TB sequential machen wie: assert(), wait for ...,
maches jenes, assert(), wait ...  klappt nur bei einfachen Dingen imo.
Bei komplizierten, sequentiell zeitlichen Zusammenhängen wird's
schnell hässlich, wenn man dann noch etwas ändert war ist die ganze
Mühe u.U. futsch, da die sorgsam eingefügten waits nicht mehr an der
Stelle stehen, wo sie sollten.

Mit reset zB. bin ich gut klargekommen mit
reset <= 0, '1', after PERIOD, '0' after 6*PERIOD, '1' after
7*PERIOD;
jetzt wollte ich das auch mal für Signalzuweisungen machen, und später
für asserts, aber es klappt leider nicht:
architecture behavior of tb_edge_trigger is 
   constant PERIOD  : time   := 10 ns;   
   signal clk      : std_logic   := '0';
   ...
   type edge_t is
   record
      at     : natural;
      rise   : std_logic_vector(7 downto 0);
      fall   : std_logic_vector(7 downto 0);
      mask   : std_logic_vector(7 downto 0);
   end record;
   type edges_t is array (8 downto 0) of edge_t;
   signal edges : edges_t;
begin
   uut: ...

   cond_setup_proc: process
   begin
      edges(0).at   <= 0;
      edges(0).rise <= b"0000_0000";
      edges(0).fall <= b"0000_0000";
      edges(0).mask <= b"0000_0000";  
            
      edges(1).at   <= 1;
      edges(1).rise <= b"0000_0001"; 
      edges(1).fall <= b"0000_0000";
      edges(1).mask <= b"0000_0001";
      ...
   end process;
       
  tb : process
  begin
    reset    <= '1',
                '0' after 1*PERIOD,
                '1' after 3*PERIOD,
                '0' after 4*PERIOD,
                '1' after 6*PERIOD,
                '0' after 7*PERIOD;
    
      for i in edges'low to edges'high loop
         -- HIER SOLLTE DIE SIGNALZUWEISUNG REIN, geht das?
      end loop;
     
      -- und hier klappt es einfach nicht
      trigger_rising <= edges(0).rise,
                        edges(1).rise after edges(1).at*PERIOD;     
    
      ...
  end process;

end;
Bei letzter Variante kommt nach run sogar:
  Delay in signal assignment is not ascending.
was ich nicht nachvollziehen kann, da at hierbei 1 ist. Die
Signalzuweisung wird auch einfach nicht durchgeführt.

Viele Grüße
Olaf

Autor: ope (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
so, jetzt wollte ich mal ganz clever sein, und einzelne Tests in einen
process packen. Allerdings zerrren jetzt die einzelnen procs
(reset_proc und test_proc) untereinander an den Signalen, hier konkret
trigger_xxxx:
architecture behavior of tb_edge_trigger is 
  constant PERIOD    : time   := 10 ns;   
  signal clk         : std_logic   := '0';
  signal reset       : std_logic   := '0';
  ...
  signal trigger_rise :  std_logic_vector(7 downto 0);
  signal trigger_fall :  std_logic_vector(7 downto 0);
  signal trigger_mask :  std_logic_vector(7 downto 0);

  signal match :  std_logic := '0';
begin

   uut: entity ...

   clock_proc: ...

   probe: ...

   ...

  reset_block: block
  begin
    reset_proc: process(reset)
    begin
      if(reset = '1') then
        trigger_rise <= b"0000_0000" after PERIOD;
        trigger_fall <= b"0000_0000" after PERIOD;
        trigger_mask <= b"0000_0000" after PERIOD;
      end if;
    end process;
    time_reset_proc: process
    begin
      reset <= '1',
               '0' after 1*PERIOD,
               '1' after 3*PERIOD,
               '0' after 4*PERIOD,
               '1' after 6*PERIOD,
               '0' after 7*PERIOD;
      wait;
    end process;
  end block;

  test_proc: process
    constant DELAY : integer := 1;
  begin       
    trigger_rise  <= b"0000_0001" after DELAY*PERIOD; 
    trigger_fall  <= b"0000_0000" after DELAY*PERIOD;
    trigger_mask  <= b"0000_0001" after DELAY*PERIOD;
    wait;
  end process;

end;

Wie bekomme ich das nun wieder korrekt hin? Da Modelsim kein Schematics
anzeigt, habe ich keine Ahnung, was 'draus gemacht wurde.

Innerhalb der Tests wollte ich dann mit assert die Ergebnisse testen
(evtl. muss ich auch einen block 'draus machen mit "stimuli" und
"check").

Viele Grüße
Olaf

Autor: ope (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
auch hier keine Hinweise? schreiben alle sequentiell mit waits?

Autor: Werner A. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
beschreib doch erstmal grundsätzlich worum es geht, pc, microcontroller,
 programmiersprache ...

Autor: ope (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann die Frage bzgl. obigen Ansatzes auch vereinfachen:

Wie kann ich in VHDL (nicht Target spezifisch) die event list (angelegt
mit
foo <= '0', '1' after X, '0' after Y ....
) in verschiedenen processes erweitern; tja, ohne die alten events zu
überschreiben bzw. ohne Kolisionen durch die Erweitung in den einzelnen
processes?

Es taucht öfters mal in den fremden sources das keyword "transport"
auf - dies hilft aber auch nicht (wenn ich es recht verstanden habe
verschiebt es ja nur die events).

Viele Grüße
Olaf

Autor: FPGA-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ope

schreib doch mal, wie Du Dir den Test des LAs vorstellst!
Nicht als VHDL, sondern verbal.

Ich könnte mir vorstellen, dass man für einzelne Module
jeweils eine TB anlegt und dann erstmal ein Modul testet.
Am Schluss gibt es eine TB für das Gesamtdesign.

Da gibt es nun mehrere Möglichkeiten. Entweder man macht
für jeden Test ein eigenes File (Stimuli_test1.vhd,
stimuli_test2.vhd ...) oder man packt eben alles in eine TB
oder ...es gibt zig weitere Varianten : TCL-Script...)

Für eine Serie von Tests würde ich mir ein Signal nehmen, dass
meine Test-Nummer speichert, z.B.:

type TEST_TYPE is (test1, test2 ...);

Dann könnte man die Testnummer entweder basierend auf der Zeit
oder auf Events hochzählen, je nachdem, wie der Testablauf
sein soll.

Alle Prozesse, die am Test beteiligt sind, können sich nun
auf dieses Signal synchronisieren. Z.B. könnte man alle Parameter
die zu Beginn des Tests gesetzt werden sollen abh. von der Test-
nummer setzen
   case test_nummer is
      when test_1 => Input_Params <= Param_Set1;
      when test_2 => ...;

Natürlich dürfen verschiedene Prozesse nicht auf 1 Signal
zugreifen, aber dafür sehe ich auch keinen Grund.

Vielleicht hilft Dir auch eine Statemachine in der Testbench.
So kompliziert kann der LA doch nicht sein, dass man dafür
keine einfache TB schreiben kann.

Autor: ope (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich könnte mir vorstellen, dass man für einzelne Module
>jeweils eine TB anlegt und dann erstmal ein Modul testet.
>Am Schluss gibt es eine TB für das Gesamtdesign.

so handhabe ich es derzeit auch - jede entity (zB. trigger_edge,
trigger_pattern) hat ihren eigenen Testbench TB_xyz, wobei ich einem
Bottom-up Entwurf fröne. Somit bekommen die Top entity (zB. trigger,
instanziert trigger_edge, trigger_pattern u.a.) einen weiteren, eigenen
TB.

Exemplarisch versuche ich es mal mit dem edge_trigger, da dazu schon
etwas in vhdl hier steht. Der Test geht zB. auf

* die Erkennung von rising edge vom sample bit0 in bitmuster (bm) #0,
anschl.
* Erkennung falling edge sample bit 3 in bm #1
* Erkennung rise/falling edge sample bit 2,3 in bm #2
* Erkennung any edge edge sample bit 5 in bm #3
* Erkennung rise/falling/any edge sample bit 0,2,6,5,8 in bm #4

Somit habe ich versch. Kombis durch. Das Bitmuster generiert derzeit
einfach nur ein counter (d.h. ist einfach eine Binärzahl), der
TB_trigger läuft mit einem prbs signal.

clock läuft hoch und bietet mir immer neue pattern, auf die ich
triggere - eben sequentiell. Das heisst, das Timing bzw. die
Reihenfolge wie ich den vhdl TB schreibe ist sehr starr und unflexibel.
Eine Änderung darin und schon stimmt es nicht mehr und das assert (will
nicht immer waves anschauen) ist an der falschen Stelle - das ist mir
nun zu oft passiert.

Daher die Idee, diese fünf Bitmuster jeweils einzeln als absolute Zeit
in einem process anzugeben - dies geschieht ja bei der event Vergabe
mit after ...

>Natürlich dürfen verschiedene Prozesse nicht auf 1 Signal
>zugreifen, aber dafür sehe ich auch keinen Grund.

Dies ist der Grund für meinen Ärger oben. Anscheinend gehts wirklich
nicht, daher sind Alternativen gesucht.

>schreib doch mal, wie Du Dir den Test des LAs vorstellst!
>Nicht als VHDL, sondern verbal.

OK, also. In einer Stelle, process, file, entity setze ich jeweils die
5 Testkonditions, zB cond_1:
        trigger_rise <= b"0000_1010";
        trigger_fall <= b"0000_1001";
        trigger_mask <= b"0000_1011";
        time := 30 ns;
Diese signale werden zur absoluten Zeit (t0+time ns) aktiv. Damit kann
ich zu jedem beliebigen Zeitpunkt meine trigger pattern setzen. Das uut
triggert zB. mit steigender clk Flanke und setzt den output match auf
'1' mit der fallenden Flanke clk. Mit der nächsten steigenden soll
assert prüfen, ob es true ist - also genau einen Taktzyklus später.
Anschliessend muss ich das uut wieder reseten um den Urzustand wieder
herzustellen, oder div. enable signal zu setzten und kann mit der
nächsten cond weiter machen (derweil mein bm generator ja weiter zählt
und andere bitmuster liefert).

Ziel ist also, diese 5 mini TB, bei denen es einzeln geschrieben und
gestartet keine Probleme geben würde, in einem grossen zu verpacken, so
dass ich weitere Testfälle vorne oder hinten anhängen kann.

Je mehr entities ich in den Tops instanziert habe, desto komplizierter
werden die Testfälle, da nun zB. "edges match, pattern matches for 5
clk cycles" etc. als cond. auftreten können. Alles kann ich nicht
testen, aber zumindest das Offensichtliche.

Viele Grüße
Olaf

Autor: ope (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soll ich weiter ausführen?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.