Erste Schritte mit Verilog (7) (Aufgaben, Funktionen)

Aufgabe

Eine Aufgabe ist wie ein Prozess, der gemeinsame Codesegmente von verschiedenen beschriebenen Orten ausführt. Ein allgemeiner Code wird mithilfe einer Aufgabendefinition als Aufgabe geschrieben, sodass er über Aufgabenaufrufe von verschiedenen Stellen in der Entwurfsbeschreibung aufgerufen werden kann. Aufgaben können eine Zeitsteuerung, also eine Verzögerungssteuerung, umfassen, und Aufgaben können auch andere Aufgaben und Funktionen aufrufen.

Aufgabendefinition

Die Form der Aufgabendefinition ist wie folgt:

task task_id;
  [declarations]
  procedural_statement
endtask

Aufgaben können keinen oder einen oder mehrere Parameter haben. Über Parameter werden Werte in und aus Aufgaben übergeben. Neben Eingabeparametern (Parameter, die Werte von der Aufgabe empfangen) können Aufgaben auch Ausgabeparameter (die Werte von der Aufgabe zurückgeben) sowie Eingabe- und Ausgabeparameter haben. Die Definition der Aufgabe ist im Abschnitt Modulbeschreibung niedergeschrieben. Zum Beispiel:

module Has_Task;
  parameter MAXBITS = 8;

  task Reverse_Bits;
    input[MAXBITS-1:0] Din;
    output[MAXBITS-1:0] Dout;
    integer K;

    begin
      for(K=0; K<MAXBITS; K=K+1)
        Dout[MAXBITS-K] = Din[K]
    end
  endtask
endmodule

Die Ein- und Ausgänge einer Aufgabe werden zu Beginn der Aufgabe deklariert. Die Reihenfolge dieser Ein- und Ausgaben bestimmt deren Reihenfolge beim Aufgabenaufruf.

Aufgabenaufruf

Eine Aufgabe wird durch eine Aufgabenaufrufanweisung aufgerufen. Die Task-Call-Anweisung gibt die an die Task übergebenen Parameterwerte und die Variablenwerte an, um die Ergebnisse zu erhalten. Die Task-Call-Anweisung ist eine prozedurale Anweisung und kann in der always-Anweisung oder der initial-Anweisung verwendet werden. Das Formular lautet wie folgt:

task_id[(expr1, expr2, ..., exprN)];

Die Parameterliste in der Aufgabenaufrufanweisung muss mit der Reihenfolge der Eingabe-, Ausgabe- und Eingabe- und Ausgabeparameterbeschreibungen in der Aufgabendefinition übereinstimmen. Darüber hinaus müssen Parameter als Wert und nicht als Adresse übergeben werden. Das Folgende ist ein Beispiel für den Aufruf der Aufgabe Reverse_Bits:

reg[MAXBITS-1:0] Reg_X, New_Reg;
Reverse_Bits(Reg_X, New_Reg)

Beachten Sie, dass die Aufgabe nach einer bestimmten Verzögerung nach dem Aufruf einen Wert zurückgeben kann, da Aufgaben eine Zeitsteuerung beinhalten können. Da es sich bei der Task-Call-Anweisung um eine prozedurale Anweisung handelt, müssen die Ausgabe-, Eingabe- und Ausgabeparameter im Task-Call vom Registertyp sein.

Mithilfe der Task-Task wird der Vergleich und die Anordnung der vier 4-Bit-Eingabedaten abgeschlossen.

module sort4data(a,b,c,d,ra,rb,rc,rd);
  input[3:0] a,b,c,d;
  output[3:0] ra,rb,rc,rd;
  reg[3:0] ra,rb,rc,rd;
  reg[3:0] va,vb,vc,vd;
  always@(a or b or c or d) begin
    {
    
    va,vb,vc,vd} = {
    
    a,b,c,d};
    sort2(va,vc);
    sort2(vb,vd);
    sort2(va,vb);
    sort2(vc,vd);
    sort2(vb,vc);
    {
    
    ra,rb,rc,rd} = {
    
    va,vb,vc,vd};
  end

  task sort2;
    inout[3:0] x,y;
    reg[3:0] tmp;
    if(x>y) begin tmp=x; x=y; y=tmp; end
  endtask
endmodule

Funktion

Funktionen können wie Aufgaben auch gemeinsamen Code an verschiedenen Stellen im Modul ausführen. Der Unterschied zwischen einer Funktion und einer Aufgabe besteht darin, dass eine Funktion nur einen Wert zurückgeben kann, keine Verzögerung oder Zeitsteuerung enthalten kann (sie muss sofort ausgeführt werden) und keine anderen Aufgaben aufrufen kann. Darüber hinaus muss die Funktion mindestens eine Eingabe annehmen, und in der Funktion ist keine Ausgabe oder Eingabe-Ausgabe-Spezifikation zulässig. Funktionen können andere Funktionen aufrufen.

Funktionsbeschreibungsteil

Der Funktionsbeschreibungsteil kann an einer beliebigen Stelle in der Modulbeschreibung erscheinen. Die Eingabe der Funktion wird durch die Eingabebeschreibung in der folgenden Form angegeben:

function[range] function_id;
  input_declaration
  other_declarations
  procedural_statament
endfunction

Funktionsbeispiele sind wie folgt:

module Function_Example
  parameter MAXBITS = 8;

  function[MAXBITS-1:0] Reverse_Bits;
    input[MAXBITS-1:0] Din;
    integer K;
    begin
      for(K=0; K<MAXBITS; K=K+1)
        Reverse_Bits[MAXBITS-K] = Din[K];
    end
  endfunction
endmodule

Die Funktionsdefinition deklariert implizit eine Registervariable innerhalb der Funktion, die denselben Namen wie die Funktion und denselben Wertebereich hat. Eine Funktion gibt einen Funktionswert zurück, indem sie diesem Register in der Funktionsdefinition explizit einen Wert zuweist. Die Zuordnung zu diesem Register muss in der Funktionsdefinition erscheinen.

Funktionsaufruf

Funktionsaufrufe sind Teil von Ausdrücken. Das Formular lautet wie folgt:

func_id(expr1, expr2,..., exprN)

Das Folgende ist ein Beispiel für einen Funktionsaufruf:

reg[MAXBITS-1:0] New_Reg, Reg_X;
New_Reg = Reverse_Bits(Reg_X);

Ähnlich wie bei Aufgaben sind alle in einer Funktionsdefinition deklarierten lokalen Register statisch, d. h. lokale Register innerhalb einer Funktion behalten ihre Werte über mehrere Aufrufe der Funktion hinweg.

Entwerfen Sie eine faktorielle Operationsschaltung mithilfe einer Aufruffunktion.

module factorial_fun(clk, n, result, reset);
  input[3:0] n;
  input clk, reset;
  output[31:0] result;
  reg[31:0] result;
  always@(posedge clk or negedge reset)
    if(!reset) result <= 0;
    else result <= factorial(n);
  function[31:0] factorial;
    input[3:0] operand;
    reg[3:0] index;
    begin factorial = operand ? 1:0;
      for(index=2; index<=operand; index=index+1)
        factorial = index * factorial;
    end
  endfunction
endmodule

Wertänderungs-Dump-Datei

Value Change Dump (VCD)-Dateien enthalten Informationen über Änderungen der Werte bestimmter Variablen im Design. Sein Hauptzweck besteht darin, Informationen für andere Nachbearbeitungswerkzeuge bereitzustellen.

Die folgenden Systemaufgaben werden zum Erstellen und Importieren von Informationen in VCD-Dateien verwendet:

$dumpfile: Diese Systemaufgabe gibt beispielsweise den Namen der Dump-Datei an

$dumpfile("uart.dump");

dumpvars: Diese Systemaufgabe gibt an, welche Variablen in die Dump-Datei geschrieben werden, wenn sich ihre Werte ändern.

dumpoff: Diese Systemaufgabe führt dazu, dass die Dump-Aufgabe angehalten wird.

dumplimit: Diese Systemaufgabe gibt die maximale Länge (Bytes) für VCD-Dateien an. Der Dump stoppt, wenn diese Grenze erreicht ist.

dumpflush: Diese Systemaufgabe aktualisiert die Daten im VCD-Dateipuffer des Betriebssystems und speichert die Daten in der VCD-Datei. Nach der Ausführung dieser Systemaufgabe befindet sich die Dump-Aufgabe im Aufwachzustand.

Hier ist ein Beispiel für einen umkehrbaren Zähler, der zwischen 5 und 12 zählt:

module CountUpDown(Clk, Count, Up_Down);
  input Clk, Up_Down;
  output[0:3] Count;
  reg[0:3] Count;

  initial Count = 'd5;

  always@(posedge Clk) begin
    if(Up_Down)
      begin
        Count = Count + 1;
        if(Count > 12)
          Count = 12
      end
    else
      begin
        Count = Count - 1;
        if(Count < 5)
          Count = 5;
      end
  end
endmodule

module Test;
  reg Clock, UpDn;
  wire[0:3] Cnt_Out;
  parameter ON_DELAY = 1, OFF_DELAY = 2;

  CountUpDown C1(Clock, Cnt_Out, UpDn);

  always begin
    Clock = 1;
    #ON_DELAY
    Clock = 0;
    #OFF_DELAY;
  end

  initial begin
    UpDn = 0;
    #50 UpDn = 1;
    #100 $dumpflush;
    $stop;
  end

  initial begin
    $dumpfile("count.dump");
    $dumplimit(4096);
    $dumpvars(0, Test);
    $dumpvars(0, C1.Count, C1.Clk, C1.Up_Down);
  end
endmodule

Guess you like

Origin blog.csdn.net/myDarling_/article/details/134753661