verilogAan de slag met verilog


Opmerkingen

Verilog is een hardwarebeschrijvingstaal (HDL) die wordt gebruikt voor het ontwerpen, simuleren en verifiëren van digitale circuits op gedrags- of registeroverdrachtsniveau. Het is opmerkelijk om een reden die het onderscheidt van "traditionele" programmeertalen:

  • Er zijn twee soorten toewijzingen, blokkeren en niet blokkeren, elk met hun eigen gebruik en semantiek.
  • Variabelen moeten worden gedeclareerd als single-bit breed of met een expliciete breedte.
  • Ontwerpen zijn hiërarchisch, met de mogelijkheid om modules met een gewenst gedrag te instantiëren.
  • In simulatie (meestal niet in synthese) kunnen wire zich in een van de vier toestanden bevinden: 0, 1, zwevend ( z ) en ongedefinieerd ( x ).

versies

Versie Publicatiedatum
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
SysteemVerilog IEEE-1800-2009 2009-12-11
SystemVerilog IEEE-1800-2012 2013/02/21

Invoering

Verilog is een hardware description language (HDL) die wordt gebruikt om elektronische systemen te modelleren. Het beschrijft meestal een elektronisch systeem op het registeroverdrachtsniveau (RTL) van abstractie. Het wordt ook gebruikt bij de verificatie van analoge circuits en circuits met gemengd signaal. De structuur en belangrijkste principes (zoals hieronder beschreven) zijn ontworpen om een elektronisch systeem te beschrijven en succesvol te implementeren.

  • Stijfheid
    Een elektronisch circuit is een fysieke entiteit met een vaste structuur en Verilog is daarop aangepast. Modules (module), poorten (input / output / inout), verbindingen (draden), blokken (@altijd), registers (reg) zijn allemaal vast tijdens het compileren. Het aantal entiteiten en interconnecties verandert niet dynamisch. Er is altijd een "module" op het hoogste niveau die de chipstructuur vertegenwoordigt (voor synthese), en een op het systeemniveau voor verificatie.
  • Parallelism
    De inherente gelijktijdige bewerkingen in de fysieke chip worden in de taal nagebootst door altijd (meeste commmon), initiële en vork / join-blokken.
  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
 

Alle bovenstaande verklaringen worden parallel binnen dezelfde tijdseenheid uitgevoerd.

  • Timing en synchronisatie
    Verilog ondersteunt verschillende constructies om de temporele aard van circuits te beschrijven. Timings en vertragingen in circuits kunnen worden geïmplementeerd in Verilog, bijvoorbeeld door #delay constructs. Evenzo is Verilog ook geschikt voor synchrone en asynchrone circuits en componenten zoals flops, latches en combinatorische logica met behulp van verschillende constructies, bijvoorbeeld "altijd" -blokken. Een set blokken kan ook worden gesynchroniseerd via een gemeenschappelijk kloksignaal of een blok kan worden geactiveerd op basis van een specifieke set ingangen.

    #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
     
  • Onzekerheid
    Verilog ondersteunt een deel van de onzekerheid die inherent is aan elektronische schakelingen. "X" wordt gebruikt om een onbekende toestand van het circuit weer te geven. "Z" wordt gebruikt om de niet-aangedreven toestand van het circuit weer te geven.

    reg1 = 1'bx;
    reg2 = 1'bz;
     
  • Abstractie
    Verilog ondersteunt ontwerpen op verschillende abstractieniveaus. Het hoogste abstractieniveau voor een ontwerp is het Resister-overdrachtsniveau (RTL), het volgende is het poortniveau en het laagste het celniveau (User Define Primitives), waarbij RTL-abstractie het meest wordt gebruikt. Verilog ondersteunt ook het gedragsniveau van abstractie zonder rekening te houden met de structurele realisatie van het ontwerp, voornamelijk gebruikt voor verificatie.

 // 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
 

Er zijn drie belangrijke gebruikstoepassingen voor Verilog. Ze bepalen de structuur van de code en de interpretatie ervan en bepalen ook de gebruikte gereedschapssets. Alle drie de applicaties zijn nodig voor een succesvolle implementatie van elk Verilog-ontwerp.

  1. Fysiek ontwerp / back-end
    Hier wordt Verilog gebruikt om het ontwerp primair te zien als een matrix van onderling verbonden poorten die een logisch ontwerp implementeren. RTL / logic / Design doorloopt verschillende stappen van synthese -> plaatsing -> klokboomconstructie -> routing -> DRC -> LVS -> naar tapeout. De precieze stappen en sequenties variëren op basis van de exacte aard van de implementatie.
  2. Simulatie
    In dit geval is het primaire doel om testvectoren te genereren om het ontwerp volgens de specificatie te valideren. De code die in deze use case is geschreven, hoeft niet te worden gesynthetiseerd en blijft binnen de verificatiesfeer. De code lijkt hier meer op generieke softwarestructuren zoals for / while / do loops etc.
  3. Ontwerp
    Ontwerp omvat het implementeren van de specificatie van een circuit in het algemeen op het RTL-abstractieniveau. De Verilog-code wordt vervolgens gegeven voor verificatie en de volledig geverifieerde code wordt gegeven voor fysieke implementatie. De code is geschreven met alleen de synthetiseerbare constructies van Verilog. Bepaalde RTL-coderingsstijl kan leiden tot simulatie versus synthese-mismatch en voorzichtigheid is geboden om deze te vermijden.

Er zijn twee belangrijke implementatiestromen. Ze hebben ook invloed op de manier waarop Verilog-code wordt geschreven en geïmplementeerd. Bepaalde codeerstijlen en bepaalde structuren zijn geschikter in de ene stroom over de andere.

  • ASIC Flow (applicatiespecifiek geïntegreerd circuit)
  • FPGA Flow (Field-programmable gate array) - inclusief FPGA en CPLD's

Hallo Wereld

Dit voorbeeld gebruikt de icarus verilog-compiler.

Stap 1: Maak een bestand met de naam 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
 

Stap 2. We compileren het .v-bestand met behulp van icarus:

>iverilog -o hello.vvp hello.v
 

De schakelaar -o wijst een naam toe aan het uitvoerobjectbestand. Zonder deze schakelaar zou het uitvoerbestand a.out worden genoemd. De hello.v geeft het te compileren bronbestand aan. Er zou praktisch geen uitvoer moeten zijn wanneer u deze broncode compileert, tenzij er fouten zijn.

Stap 3. U bent klaar om dit Hello World verilog-programma te simuleren. Gebruik hiervoor als zodanig:

>vvp hello.vvp 
Hello World!
>
 

Installeer GTKWave voor grafische weergave van simulatiegegevens op Mac OSx Sierra

GTKWave is een volledig grafisch weergavepakket dat verschillende grafische gegevensopslagstandaarden ondersteunt, maar het ondersteunt ook VCD, het formaat dat vvp zal uitvoeren. Dus om GTKWave op te halen, heb je een paar opties

  1. Ga naar http://gtkwave.sourceforge.net/gtkwave.zip en download het. Deze versie is meestal de nieuwste.
  2. Als u MacPorts hebt geïnstalleerd ( https://www.macports.org/ ), voert sudo port install gtkwave gewoon sudo port install gtkwave . Dit zal waarschijnlijk willen installeren op de afhankelijkheden om. Merk op dat je met deze methode meestal een oudere versie krijgt. Als MacPorts niet is geïnstalleerd, is er een voorbeeld van een installatie-instelling om dit op deze pagina te doen. Ja! U hebt alle xcode-ontwikkeltools nodig, omdat deze methode u een GTKWave vanaf de bron "bouwt".

Wanneer de installatie is voltooid, wordt u mogelijk gevraagd om een python-versie te selecteren. Ik had al 2.7.10 geïnstalleerd, dus ik heb nooit een nieuwe "geselecteerd".

Op dit punt kunt u gtkwave starten vanaf de opdrachtregel met gtkwave . Wanneer het wordt gestart, wordt u mogelijk gevraagd XQuarts te installeren of bij te werken. Doen. In mijn geval is XQuarts 2.7.11 geïnstalleerd.

Opmerking: ik moest eigenlijk opnieuw opstarten om XQuarts correct te krijgen, daarna heb ik gtkwave opnieuw getypt en de applicatie verschijnt.

In het volgende voorbeeld zal ik twee onafhankelijke bestanden maken, een testbank en een module om te testen, en we zullen de gtkwave gebruiken om het ontwerp te bekijken.

Installatie van Icarus Verilog Compiler voor Mac OSX Sierra

  1. Installeer Xcode vanuit de App Store.
  2. Installeer de Xcode-ontwikkeltools
> xcode-select --install
 

Dit biedt eenvoudige opdrachtregelprogramma's zoals gcc en make

  1. Installeer Mac-poorten https://www.macports.org/install.php

Het OSX Sierra-installatiepakket biedt een open-source methode voor het installeren en upgraden van extra softwarepakketten op het Mac-platform. Denk yum of apt-get voor de Mac.

  1. Installeer icarus met behulp van Mac-poorten
> sudo port install iverilog
 
  1. Controleer de installatie vanaf de opdrachtregel
$ 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.
$
 

U bent nu klaar om uw eerste Verilog-bestand op de Mac te compileren en te simuleren.

Installatie of instellingen

Gedetailleerde instructies voor het instellen of installeren van Verilog zijn afhankelijk van de tool die u gebruikt, omdat er veel Verilog-tools zijn.

Icarus Verilog en GTKWaves gebruiken om een ontwerp grafisch te simuleren en te bekijken

Dit voorbeeld gebruikt Icarus en GTKWave. Installatie-instructies voor deze tools op OSx vindt u elders op deze pagina.

Laten we beginnen met het moduleontwerp. Deze module is een BCD tot 7 segment display. Ik heb het ontwerp op een stompe manier gecodeerd, gewoon om ons iets te geven dat gemakkelijk te breken is en we kunnen een tijdje besteden aan grafische oplossingen. We hebben dus een klok, reset, een 4-gegevensingang die een BCD-waarde vertegenwoordigt, en een 7-bits uitgang die de weergave met zeven segmenten vertegenwoordigen. Maak een bestand met de naam bcd_to_7seg.v en plaats de onderstaande bron erin.

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
 

Vervolgens hebben we een test nodig om te controleren of deze module correct werkt. De casusverklaring in de testbank is naar mijn mening eigenlijk beter leesbaar en duidelijker wat het doet. Maar ik wilde niet hetzelfde statuut in het ontwerp EN in de test plaatsen. Dat is een slechte gewoonte. Er worden eerder twee onafhankelijke ontwerpen gebruikt om elkaar te valideren.

Binnen de onderstaande code ziet u twee regels $dumpfile("testbench.vcd"); en $dumpvars(0,testbench); . Deze lijnen maken het VCD-uitvoerbestand dat wordt gebruikt om een grafische analyse van het ontwerp uit te voeren. Als u ze weglaat, krijgt u geen VCD-bestand gegenereerd. Maak een bestand met de naam testbench.v en plaats de onderstaande bron erin.

`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
 

Nu we twee bestanden hebben, een testbench.v en bcd_to_7seg.v, moeten we compileren, uitwerken met Icarus. Om dit te doen:

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

Vervolgens moeten we simuleren

$ 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. 
 

Als u nu wilt valideren dat het bestand echt wordt getest, gaat u naar het bestand bcd_2_7seg.v en verplaatst u een deel van de logica en herhaalt u die eerste twee stappen.

Als voorbeeld wijzig ik de regel seg_c <= #TP bcd != 2; naar seg_c <= #TP bcd != 4; . Hercompileren en simuleren doet het volgende:

$ 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.
$
 

Laten we nu de simulatie bekijken met GTKWave. Geef een vanaf de opdrachtregel op

gtkwave testbench.vcd &

Wanneer het GTKWave-venster verschijnt, ziet u in het vak linksboven de modulenaam testbank. Klik Het. Dit onthult de submodules, taken en functies die aan dat bestand zijn gekoppeld. Draden en registers verschijnen ook in het vak linksonder.

Sleep nu, clk, bcd, error_count en seven_seg_display naar het seinvak naast het golfvormvenster. De signalen worden nu uitgezet. Error_count zal u tonen welke specifieke BCD-input de verkeerde seven_seg_display-output heeft gegenereerd.

U bent nu klaar om grafisch een probleem met een Verilog-probleem op te lossen.