Verilog 入門 (6) 行動モデリング

プロセス構造

次の 2 つのステートメントは、デザインの動作をモデル化するための主要なメカニズムです。

  1. initial声明
  2. always声明

モジュールには、initial または always ステートメントをいくつでも含めることができます。これらのステートメントは互いに並列して実行されます。つまり、これらのステートメントが実行される順序は、モジュール内の順序とは無関係です。 initial または always ステートメントを実行すると、すべての initial ステートメントと always ステートメントに対して単一の制御フローが生成されます。時刻 0 で並列実行を開始します。

initial声明

initial ステートメントは 1 回だけ実行されます。 initial ステートメントは、シミュレーションの開始時、つまり時間 0 に実行されます。構文は次のとおりです。

initial
[timing control] procedural_statement

procedural_statement次のステートメントのいずれかです。

  • procedural_assignment (ブロッキングまたはノンブロッキング)
  • procedural_continuous_assignment
  • 条件文
  • ケースステートメント
  • ループステートメント
  • wait_statement
  • 無効化ステートメント
  • イベントトリガー
  • シーケンシャルブロック
  • 並列ブロック
  • タスク有効化

シーケンシャル プロシージャ (begin...end) は、プロセス ステートメントで最も一般的に使用されます。ここでのタイミング制御には、遅延制御、つまり特定の時間待機することも、イベント制御、つまり特定のイベントが発生するか特定の条件が真になるのを待機することもできます。

always声明

initial ステートメントとは異なり、always ステートメントは繰り返し実行されます。 initial ステートメントと同様、always ステートメントの構文は次のとおりです。

always
  [timing control] procedural_statement

たとえば、クロック周期 10 の波形を生成するには、次のようにします。

always
  #5 clk = ~ clk;

次の例は、イベントによって制御されるシーケンス プロセスですalways ステートメント:

reg[0:5] InstrReg;
reg[3:0] Accum;
wire ExecuteCycle;

always@(ExecuteCycle)
  begin
    case(InstrReg[0:1])
      2'b00: Store(Accum, InstrReg[2:5]);
      2'b11: Load(Accum, InstrReg[2:5]);
      2'b01: Jump(InstrReg[2:5]);
      2'b10:;
    endcase
  end
  // Store、Load 和 Jump 是在别处定义的用户自定义的任务

イベント制御

イベント制御では、イベントに基づいてalwaysの手続き文が実行されます。イベント コントロールには 2 つのタイプがあります。

  1. エッジトリガーイベント制御
  2. レベルに応じたイベント制御

エッジ トリガー イベント コントロールは次のとおりです。

@ event procedural_statement

次の例に示すように:

@(posedge clock)
curr_state = next_state

イベント制御を使用したプロセスまたはプロシージャ ステートメントの実行は、指定されたイベントが発生するまで待機する必要があります。上記の例では、clock 信号がロー レベルからハイ レベルに変化した場合 (ポジティブ エッジ)、代入ステートメントが実行されます。そうでない場合、プロセスは clock 信号は次のポジティブエッジを生成します。

レベル依存のイベント制御では、プロセス ステートメントまたはプロセス内の手続きステートメントの実行は、条件が true になるまで遅延されます。レベル依存のイベント コントロールは次の形式で提供されます。

wait(Condition)
  procedural_statement

手続き型ステートメントは、条件が true の場合にのみ実行され、それ以外の場合、手続き型ステートメントは条件が true になるまで待機します。ステートメントの実行時に条件がすでに true である場合、手続き型ステートメントは直ちに実行されます。上記の表現では、手続きステートメントはオプションです。

ステートメントブロック

ステートメント ブロックは、2 つ以上のステートメントを文法的に単一のステートメントと同等に結合するメカニズムを提供します。 Verilog には、次の 2 種類のステートメント ブロックがあります。

  1. シーケンシャル ステートメント ブロック (begin...end): ステートメント ブロック内のステートメントは、指定された順序で順次実行されます。
  2. 並列ステートメント ブロック (fork...join): ステートメント ブロック内のステートメントは並列で実行されます。

シーケンスブロック

シーケンシャル ステートメント ブロック内のステートメントは、順番に実行されます。各ステートメントのレイテンシー値は、前のステートメントの実行のシミュレーション時間に関連しています。シーケンスブロックの実行が終了すると、シーケンスブロックの処理に続く次のステートメントの実行が継続されます。順次ステートメント ブロックの構文は次のとおりです。

begin
  [:block_id{
    
    declarations}]
  procedural_statement(s)
end

例えば

begin
  #2 Stream = 1;
  #5 Stream = 0;
  #3 Stream = 1;
  #4 Stream = 0;
  #2 Stream = 1;
  #5 Stream = 0;
end

ステートメントの連続ブロックが 10 番目の時間単位で実行を開始すると仮定します。最初のステートメントは 2 時間単位後、つまり 12 番目の時間単位後に実行されます。この実行が完了すると、次のステートメントが 17 時間単位で実行されます (5 時間単位遅延)。次に、次のステートメントが 20 番目の時間単位で実行され、以下同様に続きます。

パラレルステートメントブロック

並列ステートメント ブロック内の各ステートメントは並列に実行されます。パラレル ステートメント ブロック内の各ステートメントによって指定される遅延値は、ステートメント ブロックが実行を開始する時間に関連します。並列ステートメント ブロック内の最後のアクションが実行されると (最後のアクションが最後のステートメントであるとは限りません)、シーケンシャル ステートメント ブロック内のステートメントは引き続き実行されます。つまり、パラレル ステートメント ブロック内のすべてのステートメントは、制御がステートメント ブロックの外に移される前に実行を完了する必要があります。例えば

fork
  #2 Stream = 1;
  #7 Stream = 0;
  #10 Stream = 1;
  #14 Stream = 0;
  #16 Stream = 1;
  #21 Stream = 0;
join

並列ステートメント ブロックがタイム ユニット 10 で実行を開始すると、すべてのステートメントが並列で実行され、すべての遅延はタイム ユニット 10 を基準とします。たとえば、3 番目の割り当ては 20 番目の時間単位で実行され、5 番目の割り当ては 26 番目の時間単位で実行されます。

手続き的な割り当て

手続き型代入は、initial または always ステートメント内の代入であり、 はレジスタ データにのみ使用できます。変数の割り当てをタイプします。

手続きの割り当ては、次の 2 つのカテゴリに分類されます。

  1. ブロッキングプロシージャの割り当て
  2. ノンブロッキング手続き型代入

ブロッキングプロシージャの割り当て

代入演算子は です。= の手続き型代入はブロッキング手続き型代入です。ブロッキング プロシージャの代入は、後続のすべてのステートメントが実行される前に実行されます。つまり、次のステートメントが実行される前に代入ステートメントの実行が完了します。

ノンブロッキング手続き型代入

ノンブロッキング手続き型代入では、代入記号 <= を使用します。

ノンブロッキング プロシージャル割り当てでは、ターゲットへの割り当ては (レイテンシのため) ノンブロッキングですが、(レイテンシに応じて) 将来のタイム ステップで実行されるようにスケジュールできます。レイテンシが 0 の場合、現在のタイム ステップで終了します。 )。

begin
  Load <= 32;
  RegA <= Load;
  RegB <= Store;
end

ノンブロッキング手続き型代入が実行されると、右側の式が評価され、右側の値が左側のターゲットに割り当てられ、実行が次のステートメントに続きます。上の例では、ステートメントの連続ブロックが時刻 10 に実行されると想定しています。最初のステートメントにより、10 番目の時間単位の終了時に Load に値 32 が割り当てられます。その後、2 番目のステートメントが実行され、Load の値は残ります。変更されていない場合 (時間がまだ進んでおらず、最初の割り当てにまだ新しい値が割り当てられていないことに注意してください)、RegA の割り当ては 10 番目のタイム ステップの終わりにスケジュールされます。すべてのイベントが 10 番目の時間単位で発生した後、左端のターゲットへのスケジュールされた割り当てがすべて完了します。

以下はブロッキングプロシージャ代入とノンブロッキングプロシージャ代入を両方使用する例ですが、両者の違いに注意してください。

reg[0:2] Q_State;

initial begin
  Q_state = 3'b011;
  Q_state <= 3'b100;
  $display("Current value of Q_State is %b", Q_State);
  #5;
  $display("The delayed value of Q_State is %b", Q_State);
end

initial ステートメントを実行すると、次の結果が生成されます:

Current value of Q_State is 011
The delayed value of Q_State is 100

if声明

ifステートメントの構文は次のとおりです。

if(condition_1)
  procedural_statement_1
{
    
    else if(condition_2)
  procedural_statement_2}
{
    
    else
  procedural_statement_3}

条件式は常に囲む必要があることに注意してください。if-if-else 形式を使用する場合、次の例に示すようにあいまいさが生じる可能性があります。

if(clk)
  if(Reset)
    Q = 0;
  else
    Q = D;

問題は、最後の else がどの if に属するかということです。 Verilog は、else を、else を持たない最も近い if に関連付けます。

case声明

caseこのステートメントは複数方向の条件分岐形式であり、その構文は次のとおりです。

case(case_expr)
  case_item_expr{
    
    , case_item_expr}: procedural_statement
  ...
  ...
  [default: procedural_statement]
endcase

caseステートメント 1 の例は次のとおりです。

module ALU(A, B, OpCode, Z);
  input[3:0] A, B;
  input[1:2] OpCode;
  output[7:0] Z;
  reg[7:0] Z;
parameter
  ADD_INSTR = 2'b10,
  SUB_INSTR = 2'b11,
  MUL_INSTR = 2'b01,
  DIV_INSTR = 2'b00;
always@(A or B or OpCode)
  case(OpCode)
    ADD_INSTR: Z = A + B;
    SUB_INSTR: Z = A - B;
    MUL_INSTR: Z = A * B;
    DIV_INSTR: Z = A / B;
  endcase
endmodule

ループ文

Verilog には 4 種類のループ ステートメントがあります。

  1. foreverサイクル
  2. repeatサイクル
  3. whileサイクル
  4. forサイクル

foreverサイクル

foreverループの構文は次のとおりです。

forever
  procedural_statement

このループ ステートメントは、手続き型ステートメントを継続的に実行します。したがって、このようなループから抜け出すために、abort ステートメントを手続き型ステートメントと一緒に使用できます。また、プロシージャ ステートメントでは何らかの形式のタイミング制御を使用する必要があります。そうしないと、forever ループは遅延 0 の後に永久にループします。

initial begin
  clock = 0;
  #5 forever
    #10 clock = ~clock;
end

この例ではクロック波形を生成します。クロックは最初に 0 に初期化され、5 番目の時間単位までそのままになります。その後、10 時間単位ごとに clock が反転します。

repeatループ文

repeatループステートメントの形式は次のとおりです。

repeat(loop_count)
  procedural_statement

このループ ステートメントは、指定された回数のループに対して手続き型ステートメントを実行します。ループ回数式の値が不定の場合、つまりxまたはzの場合、ループ回数は0として扱われます。

whileループ文

whileループ ステートメントの構文は次のとおりです。

while(condition)
  procedural_statement

このループ ステートメントは、指定された条件が false になるまで、プロセス代入ステートメントをループします。式の最初が false の場合、手続きステートメントは実行されません。

while(By > 0)
  begin
    Acc = Acc << 1;
    By = by - 1;
  end

forループ文

forループ ステートメントの形式は次のとおりです。

for(initial_assignment;condition;step_assignment)
  procedural_statement

for ループ ステートメントは、プロシージャ代入ステートメントの実行を指定された回数繰り返します。初期代入 initial_assignment はループ変数の初期値を与えます。 condition 条件式は、どのような状況でループを終了する必要があるかを指定します。条件が true である限り、ループ内のステートメントは実行され、step_assignment は、通常はループ変数の数を増減することによって、割り当てを変更します。

integer K;
for(K=0; K<MAX_RANGE; K=K+1)
  begin
    if(Abus[K] == 0)
      Abus[K] = 1;
    else if(Abus[K] == 1)
      Abus[K] = 0;
    else
      $display("Abus[K] is an x or a z");
  end

ハンドシェイクプロトコルの例

always ステートメントは、有限状態マシンの相互作用など、対話型プロセスの動作を記述するために使用できます。これらのモジュール内のステートメントは、すべての always ステートメントに表示されるレジスタを使用して相互に通信します。

RX 受信機と MP マイクロプロセッサという 2 つの対話プロセスの例を考えてみましょう。 RX プロセスはシリアル入力データを読み取ります。そして、 Ready シグナルを送信して、データを MP プロセスに読み込むことができることを示します。 MP プロセスはデータを出力に割り当てた後、新しい入力データを読み取るために受信信号 Ack を RX プロセスに送り返します。 2 つのプロセスのステートメント ブロック フローを次の図に示します。

ここに画像の説明を挿入します
これら 2 つの相互作用するプロセスの動作は、次の動作モデルで説明できます。

`timescale 1ns/100ps
module Interacting(Serial_In, Clk, Parallel_Out)
  input Serial_In, Clk;
  output[0:7] Parallel_Out;
  reg[0:7] Parallel_Out;
  reg Ready, Ack;
  wire[0:7] Data;

  `include "Read_Word.v"
always
  begin:RX
    Read_Word(Serial_In, Clk, Data);
    // 任务 Read_Word 在每个时钟周期读取串行数据,将其转换为并行数据并存于 Data中,完成该任务需要 10ns
    Ready = 1;
    wait(Ack);
    Ready = 0;
    #40;
  end:RX

always
  begin:MP
    #25;
    Parallel_Out = Data;
    Ack = 1;
    #25 Ack = 0;
    wait(Ready);
  end:MP
endmodule

レジスタReadyAck を介した 2 つのプロセス間の対話型ハンドシェイク プロトコルは、次の図に示すとおりです。

ここに画像の説明を挿入します

Je suppose que tu aimes

Origine blog.csdn.net/myDarling_/article/details/134734958
conseillé
Classement