Szukaj…


Uwagi

Verilog to język opisu sprzętu (HDL), który służy do projektowania, symulacji i weryfikacji obwodów cyfrowych na poziomie behawioralnym lub transferu rejestru. Jest to godne uwagi z powodów, które odróżniają go od „tradycyjnych” języków programowania:

  • Istnieją dwa rodzaje przypisywania, blokowania i nieblokowania, każdy z własnymi zastosowaniami i semantyką.
  • Zmienne należy zadeklarować jako szerokość jednego bitu lub z jawną szerokością.
  • Projekty są hierarchiczne, z możliwością tworzenia instancji modułów o pożądanym działaniu.
  • W symulacji (zwykle nie w syntezie) zmienne wire mogą znajdować się w jednym z czterech stanów: 0, 1, zmiennoprzecinkowe ( z ) i niezdefiniowane ( x ).

Wersje

Wersja Data wydania
Verilog IEEE-1364-1995 1995-01-01
Verilog IEEE-1364-2001 2001-09-28
Verilog IEEE-1364.1-2002 2002-12-18
Verilog IEEE-1364-2005 2006-04-07
SystemVerilog IEEE-1800-2009 2009-12-11
SystemVerilog IEEE-1800-2012 21.02.2013

Instalacja lub konfiguracja

Szczegółowe instrukcje konfiguracji lub instalacji Verilog zależą od używanego narzędzia, ponieważ istnieje wiele narzędzi Verilog.

Wprowadzenie

Verilog to język opisu sprzętu (HDL) używany do modelowania systemów elektronicznych. Najczęściej opisuje system elektroniczny na poziomie transferu rejestru (RTL) abstrakcji. Służy również do weryfikacji obwodów analogowych i obwodów sygnałów mieszanych. Jego struktura i główne zasady (jak opisano poniżej) mają na celu opisanie i skuteczne wdrożenie systemu elektronicznego.

  • Sztywność
    Obwód elektroniczny jest fizyczną jednostką o stałej strukturze i Verilog jest do tego przystosowany. Moduły (moduł), porty (wejście / wyjście / wejście), połączenia (przewody), bloki (@ zawsze), rejestry (reg) są ustalane w czasie kompilacji. Liczba jednostek i połączeń nie zmienia się dynamicznie. Na najwyższym poziomie zawsze znajduje się „moduł” reprezentujący strukturę chipa (do syntezy) i jeden na poziomie systemu do weryfikacji.
  • Równoległość
    Nieodłączne jednoczesne operacje na fizycznym układzie scalonym są naśladowane w języku przez bloki zawsze (najbardziej wspólne), początkowe i rozwidlające / łączące.
  module top();
  reg r1,r2,r3,r4; // 1-bit registers
    initial
    begin
      r1 <= 0 ;
    end
    initial
    begin
      fork
         r2 <= 0 ;
         r3 <= 0 ;
      join
    end
     always @(r4)
        r4 <= 0 ;
 endmodule

Wszystkie powyższe instrukcje są wykonywane równolegle w tej samej jednostce czasu.

  • Czas i synchronizacja
    Verilog obsługuje różne konstrukcje opisujące czasową naturę obwodów. Czasy i opóźnienia w obwodach można zaimplementować w Verilog, na przykład za pomocą konstrukcji #delay. Podobnie Verilog obsługuje również obwody i komponenty synchroniczne i asynchroniczne, takie jak klapy, zatrzaski i logika kombinatoryczna, wykorzystując różne konstrukcje, na przykład bloki „zawsze”. Zestaw bloków może być również synchronizowany za pomocą wspólnego sygnału zegarowego lub blok może być wyzwalany w oparciu o określony zestaw wejść.

    #10   ;                 // delay for 10 time units
    always @(posedge clk )  // synchronous 
    always @(sig1 or sig2 ) // combinatorial logic  
    @(posedge event1)       // wait for post edge transition of event1
    wait (signal  == 1)     // wait for signal to be 1
    
  • Niepewność
    Verilog obsługuje niektóre z niepewności związanych z obwodami elektronicznymi. „X” oznacza nieznany stan obwodu. „Z” służy do reprezentowania stanu nienapędzonego obwodu.

    reg1 = 1'bx;
    reg2 = 1'bz;
    
  • Abstrakcja
    Verilog obsługuje projektowanie na różnych poziomach abstrakcji. Najwyższy poziom abstrakcji dla projektu to Resister transfer Level (RTL), następny to poziom bramki, a najniższy poziom komórki (User Define Primitive), przy czym najczęściej używana jest abstrakcja RTL. Verilog obsługuje również poziom abstrakcji behawioralnej, bez względu na konstrukcyjną realizację projektu, wykorzystywaną przede wszystkim do weryfikacji.

 // Example of a D flip flop at RTL abstraction
module dff (
 clk    , // Clock Input
 reset  , // Reset input
 d       , // Data Input
 q        // Q output
 );
 //-----------Input Ports---------------
 input d, clk, reset ;

 //-----------Output Ports---------------
 output q;

 reg q;

 always @ ( posedge clk)
 if (~reset) begin
   q <= 1'b0;
 end  else begin
   q <= d;
 end

endmodule


// And gate model based at Gate level abstraction 
module and(input x,input y,output o);

wire  w;
// Two instantiations of the module NAND
nand U1(w,x, y); 
nand U2(o, w, w); 

endmodule

// Gate modeled at Cell-level Abstraction
primitive udp_and(
a, // declare three ports
b,
c 
);
output a;   // Outputs
input b,c;  // Inputs 

// UDP function code here
// A = B & C;
table
 // B  C    : A 
    1  1    : 1;
    0  1    : 0;
    1  0    : 0;
    0  0    : 0;
endtable

endprimitive

Istnieją trzy główne przypadki użycia Verilog. Określają strukturę kodu i jego interpretację, a także określają używane zestawy narzędzi. Wszystkie trzy aplikacje są niezbędne do pomyślnego wdrożenia dowolnego projektu Verilog.

  1. Projekt fizyczny / zaplecze
    Tutaj Verilog służy przede wszystkim do postrzegania projektu jako matrycy połączonych bram realizujących logiczny projekt. RTL / logika / Projektowanie przechodzi przez różne etapy od syntezy -> umieszczenia -> budowy drzewa zegarowego -> routingu -> DRC -> LVS -> do tapeout. Dokładne kroki i sekwencje różnią się w zależności od dokładnego charakteru wdrożenia.
  2. Symulacja
    W tym przypadku podstawowym celem jest wygenerowanie wektorów testowych w celu zweryfikowania projektu zgodnie ze specyfikacją. Kod napisany w tym przypadku użycia nie musi być syntezowalny i pozostaje w sferze weryfikacji. Kod tutaj bardziej przypomina ogólne struktury oprogramowania, takie jak pętle for / while / do itp.
  3. Projekt
    Projektowanie obejmuje implementację specyfikacji obwodu zasadniczo na poziomie abstrakcji RTL. Kod Verilog jest następnie podawany do weryfikacji, a kod w pełni weryfikowany do fizycznej realizacji. Kod jest napisany przy użyciu wyłącznie syntezowalnych konstrukcji Verilog. Niektóre style kodowania RTL mogą powodować niedopasowanie symulacji w porównaniu do syntezy i należy dołożyć starań, aby ich uniknąć.

Istnieją dwa główne etapy wdrażania. Wpłyną również na sposób pisania i implementacji kodu Verilog. Niektóre style kodowania i pewne struktury są bardziej odpowiednie w jednym przepływie nad drugim.

  • ASIC Flow (specyficzny dla aplikacji układ scalony)
  • FPGA Flow (programowalna tablica bramek) - obejmuje FPGA i CPLD

Witaj świecie

W tym przykładzie użyto kompilatora icarus verilog.

Krok 1: Utwórz plik o nazwie hello.v

module myModule();

initial
  begin
    $display("Hello World!");   // This will display a message
    $finish ; // This causes the simulation to end.  Without, it would go on..and on.
  end

endmodule

Krok 2. Kompilujemy plik .v przy użyciu programu icarus:

>iverilog -o hello.vvp hello.v

Przełącznik -o przypisuje nazwę do pliku obiektu wyjściowego. Bez tego przełącznika plik wyjściowy byłby nazywany a.out. Hello.v wskazuje plik źródłowy do skompilowania. Podczas kompilowania tego kodu źródłowego nie powinno być praktycznie żadnych wyników, chyba że wystąpią błędy.

Krok 3. Jesteś gotowy do symulacji tego programu Verilog Hello World. Aby to zrobić, wywołaj jako taki:

>vvp hello.vvp 
Hello World!
>

Instalacja kompilatora Icarus Verilog dla Mac OSX Sierra

  1. Zainstaluj Xcode z App Store.
  2. Zainstaluj narzędzia programistyczne Xcode
> xcode-select --install

Zapewni to podstawowe narzędzia wiersza poleceń, takie jak gcc i make

  1. Zainstaluj porty Mac https://www.macports.org/install.php

Pakiet instalacyjny OSX Sierra zapewni metodę open source do instalowania i aktualizowania dodatkowych pakietów oprogramowania na platformie Mac. Pomyśl yum lub apt-get dla Maca.

  1. Zainstaluj icarus przy użyciu portów Mac
> sudo port install iverilog
  1. Sprawdź instalację z wiersza polecenia
$ iverilog
iverilog: no source files.

Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]
                [-g1995|-g2001|-g2005] [-g<feature>]
                [-D macro[=defn]] [-I includedir] [-M depfile] [-m module]
                [-N file] [-o filename] [-p flag=value]
                [-s topmodule] [-t target] [-T min|typ|max]
                [-W class] [-y dir] [-Y suf] source_file(s)

See the man page for details.
$

Jesteś teraz gotowy do skompilowania i symulacji pierwszego pliku Verilog na komputerze Mac.

Zainstaluj GTKWave do graficznego wyświetlania danych symulacji w Mac OSx Sierra

GTKWave to w pełni funkcjonalny graficzny pakiet przeglądający, który obsługuje kilka graficznych standardów przechowywania danych, ale zdarza się również, że obsługuje VCD, który jest formatem, który vvp . Tak więc, aby podnieść GTKWave, masz kilka opcji

  1. Idź do http://gtkwave.sourceforge.net/gtkwave.zip i pobierz go. Ta wersja jest zazwyczaj najnowsza.
  2. Jeśli zainstalowałeś MacPorts ( https://www.macports.org/ ), po prostu uruchom sudo port install gtkwave . Prawdopodobnie będzie chciał zainstalować na zależnościach. Uwaga: ta metoda zazwyczaj zapewnia starszą wersję. Jeśli nie masz zainstalowanych MacPorts, na tej stronie znajduje się przykład konfiguracji instalacji. Tak! Będziesz potrzebował wszystkich narzędzi programistycznych xcode, ponieważ te metody „zbudują” ci GTKWave ze źródła.

Po zakończeniu instalacji możesz zostać poproszony o wybranie wersji Pythona. Zainstalowałem już wersję 2.7.10, więc nigdy nie „wybrałem” nowego.

W tym momencie możesz uruchomić gtkwave z wiersza poleceń za pomocą gtkwave . Po uruchomieniu może zostać wyświetlony monit o instalację lub aktualizację XQuarts. Zrób tak. W moim przypadku XQuarts 2.7.11 jest zainstalowany.

Uwaga: naprawdę potrzebowałem zrestartować się, aby poprawnie pobrać XQuarts, potem ponownie gtkwave i aplikacja się uruchomi.

W następnym przykładzie utworzę dwa niezależne pliki, testbench i moduł do testowania, i użyjemy gtkwave do przeglądania projektu.

Korzystanie z Icarus Verilog i GTKWaves do symulacji i wyświetlania projektu graficznie

W tym przykładzie wykorzystano Icarus i GTKWave. Instrukcje instalacji tych narzędzi w systemie OSx znajdują się w innym miejscu na tej stronie.

Zacznijmy od projektu modułu. Ten moduł jest wyświetlaczem BCD do 7 segmentów. Projekt zakodowałem w tępy sposób, aby dać nam coś, co łatwo zepsuć, i możemy spędzić trochę czasu na graficznym naprawie. Mamy więc zegar, reset, 4 dane wejściowe reprezentujące wartość BCD i 7 bitowe wyjście, które reprezentują siedmiosegmentowy wyświetlacz. Utwórz plik o nazwie bcd_to_7seg.v i umieść w nim źródło poniżej.

module bcd_to_7seg (
   input clk,
   input reset,
   input [3:0] bcd,
   output [6:0] seven_seg_display

);
   parameter TP = 1;
   reg seg_a;
   reg seg_b;
   reg seg_c;
   reg seg_d;
   reg seg_e;
   reg seg_f;
   reg seg_g;

   
   always @ (posedge clk or posedge reset)
      begin
      if (reset)
         begin
            seg_a <= #TP 1'b0;
            seg_b <= #TP 1'b0;
            seg_c <= #TP 1'b0;
            seg_d <= #TP 1'b0;
            seg_e <= #TP 1'b0;
            seg_f <= #TP 1'b0;
            seg_g <= #TP 1'b0;
         end
      else
         begin
            seg_a <= #TP  ~(bcd == 4'h1 || bcd == 4'h4);
            seg_b <= #TP  bcd < 4'h5 || bcd > 6;
            seg_c <= #TP   bcd != 2;
            seg_d <= #TP   bcd == 0 || bcd[3:1] == 3'b001 || bcd == 5 || bcd == 6 || bcd == 8;
            seg_e <= #TP  bcd == 0 || bcd == 2 || bcd == 6 || bcd == 8;
            seg_f <= #TP  bcd == 0 || bcd == 4 || bcd == 5 || bcd == 6 || bcd > 7;
            seg_g <= #TP  (bcd > 1 && bcd < 7) || (bcd > 7);
         end
    end
 
    assign seven_seg_display = {seg_g,seg_f,seg_e,seg_d,seg_c,seg_b,seg_a};
endmodule

Następnie potrzebujemy testu, aby sprawdzić, czy ten moduł działa poprawnie. Moim zdaniem stwierdzenie przypadku w środowisku testowym jest łatwiejsze do odczytania i bardziej jasne, co robi. Ale nie chciałem umieszczać tego samego stwierdzenia przypadku w projekcie ORAZ w teście. To zła praktyka. Raczej dwa niezależne projekty są używane do wzajemnej weryfikacji.

Korzystając z poniższego kodu, zauważysz dwie linie $dumpfile("testbench.vcd"); i $dumpvars(0,testbench); . Te wiersze tworzą plik wyjściowy VCD, który zostanie wykorzystany do graficznej analizy projektu. Jeśli je pominiesz, nie zostanie wygenerowany plik VCD. Utwórz plik o nazwie testbench.v i umieść w nim źródło poniżej.

`timescale 1ns/100ps
module testbench;
reg clk;
reg reset;
reg [31:0] ii;
reg [31:0] error_count;
reg [3:0] bcd;
wire [6:0] seven_seg_display; 
parameter TP = 1;
parameter CLK_HALF_PERIOD = 5;
 
   // assign clk = #CLK_HALF_PERIOD ~clk;  // Create a clock with a period of ten ns
   initial
   begin
     clk = 0;
     #5;
     forever clk = #( CLK_HALF_PERIOD )  ~clk;
   end

   initial
     begin
       $dumpfile("testbench.vcd");
       $dumpvars(0,testbench);
       // clk  = #CLK_HALF_PERIOD ~clk; 
       $display("%0t, Reseting system", $time);
       error_count = 0;
       bcd  = 4'h0;
       reset = #TP 1'b1;
       repeat (30) @ (posedge clk);
       reset  = #TP 1'b0;
       repeat (30) @ (posedge clk);
       $display("%0t, Begin BCD test", $time); // This displays a message


       for (ii = 0; ii < 10; ii = ii + 1)
          begin
          repeat (1) @ (posedge clk);
          bcd  = ii[3:0];
          repeat (1) @ (posedge clk); 
          if (seven_seg_display !== seven_seg_prediction(bcd)) 
             begin
                $display("%0t, ERROR: For BCD %d, module output 0b%07b does not match prediction logic value of 0b%07b.",$time,bcd, seven_seg_display,seven_seg_prediction(bcd));
                error_count = error_count + 1;
             end
          end
       $display("%0t, Test Complete with %d errors", $time, error_count);
       $display("%0t, Test %s", $time, ~|error_count ? "pass." : "fail.");
       $finish ; // This causes the simulation to end.
     end


parameter SEG_A = 7'b0000001;
parameter SEG_B = 7'b0000010;
parameter SEG_C = 7'b0000100;
parameter SEG_D = 7'b0001000;
parameter SEG_E = 7'b0010000;
parameter SEG_F = 7'b0100000;
parameter SEG_G = 7'b1000000;

function [6:0] seven_seg_prediction;
   input [3:0] bcd_in;

   //    +--- A ---+
   //    |         |
   //    F         B
   //    |         |
   //    +--- G ---+
   //    |         |
   //    E         C
   //    |         |
   //    +--- D ---+

   begin
      case (bcd_in)
         4'h0: seven_seg_prediction = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F;
         4'h1: seven_seg_prediction = SEG_B | SEG_C;
         4'h2: seven_seg_prediction = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D;
         4'h3: seven_seg_prediction = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D;
         4'h4: seven_seg_prediction = SEG_F | SEG_G | SEG_B | SEG_C;
         4'h5: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D;
         4'h6: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_E | SEG_C | SEG_D;
         4'h7: seven_seg_prediction = SEG_A | SEG_B | SEG_C;
         4'h8: seven_seg_prediction = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G;
         4'h9: seven_seg_prediction = SEG_A | SEG_F | SEG_G | SEG_B | SEG_C;
         default: seven_seg_prediction = 7'h0;
      endcase
   end
endfunction


bcd_to_7seg u0_bcd_to_7seg (
.clk               (clk),
.reset             (reset),
.bcd               (bcd),
.seven_seg_display (seven_seg_display)
);


endmodule

Teraz, gdy mamy dwa pliki, testbench.v i bcd_to_7seg.v, musimy skompilować, opracować za pomocą Icarusa. Aby to zrobić:

$ iverilog -o testbench.vvp testbench.v bcd_to_7seg.v

Następnie musimy przeprowadzić symulację

$ vvp testbench.vvp 
LXT2 info: dumpfile testbench.vcd opened for output.
0, Reseting system
6000, Begin BCD test
8000, Test Complete with          0 errors
8000, Test pass. 

W tym momencie, jeśli chcesz sprawdzić poprawność pliku, który jest naprawdę testowany, przejdź do pliku bcd_2_7seg.v i przenieś trochę logiki i powtórz pierwsze dwa kroki.

Jako przykład zmieniam wiersz seg_c <= #TP bcd != 2; do seg_c <= #TP bcd != 4; . Ponowna kompilacja i symulacja wykonuje następujące czynności:

$ iverilog -o testbench.vvp testbench.v bcd_to_7seg.v
$ vvp testbench.vvp 
LXT2 info: dumpfile testbench.vcd opened for output.
0, Reseting system
6000, Begin BCD test
6600, ERROR: For BCD  2, module output 0b1011111 does not match prediction logic value of 0b1011011.
7000, ERROR: For BCD  4, module output 0b1100010 does not match prediction logic value of 0b1100110.
8000, Test Complete with          2 errors
8000, Test fail.
$

Teraz zobaczmy symulację za pomocą GTKWave. Z wiersza polecenia wydaj a

gtkwave testbench.vcd &

Kiedy pojawi się okno GTKWave, w lewym górnym polu zobaczysz nazwę modułu testbench. Kliknij to. Ujawni to podmoduły, zadania i funkcje związane z tym plikiem. Przewody i rejestry pojawią się również w lewym dolnym polu.

Teraz przeciągnij, clk, bcd, error_count i seven_seg_display do pola sygnału obok okna kształtu fali. Sygnały zostaną teraz wykreślone. Error_count pokaże, które konkretne wejście BCD wygenerowało nieprawidłowe wyjście Seven_seg_display.

Jesteś teraz gotowy do graficznego rozwiązywania problemów z błędem Verilog.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow