LRM読解(Chap.9-4)

2008/10/04Verilog::文法import

Behavioral modeling~その4

9.8 Block statements

ブロック命令文は,互いに複数の命令文をグルーピングすることを意味しますので,それらは1つの命令文のように,ふるまいます.
Verilog-HDLには2種類のブロックがあります.

  • シーケンシャルブロック(begin-endブロック)
  • パラレルブロック(fork-joinブロック)

シーケンシャルブロックは,beginとendキーワードで区切られます.シーケンシャルブロック中の,手続き型命令文は,与えられた順にシーケンシャルに実行されます.
パラレルブロックは,forkとjoinキーワードで区切られます.パラレルブロック中の,手続き型命令文は,同時に実行されます.


9.8.1 シーケンシャルブロック ~ Sequential blocks

シーケンシャルブロックは,下記の特徴をもっています.

  • 命令文は,他のあとに1つずつシーケンシャルに実行されます.
  • 各命令文の遅延値は,前のステートメントを実行したシミュレーション時間に関連して扱われます.
  • 制御は,最後の命令文の実行後に,ブロックを抜けます.
function_seq_block ::= (From Annex A - A.6.3)
  begin [ : block_identifier { block_item_declaration } ] { function_statement } end

seq_block ::=
  begin [ : block_identifier { block_item_declaration } ] { statement } end

block_item_declaration ::= (From Annex A - A.2.8)
    { attribute_instance } block_reg_declaration
  | { attribute_instance } event_declaration
  | { attribute_instance } integer_declaration
  | { attribute_instance } local_parameter_declaration
  | { attribute_instance } parameter_declaration
  | { attribute_instance } real_declaration
  | { attribute_instance } realtime_declaration
  | { attribute_instance } time_declaration

Example 1
シーケンシャルブロックは,決定論的な結果を持つために,下記の2つの代入を有効にします.

原文を置いておきます... イマイチ.
 A sequential block enables the following two assignments to have a deterministic result:
begin
  areg = breg;
  creg = areg; // creg stores the value of breg
end

1つ目の代入は実行され,2つ目の代入に制御が移る前にaregは更新される.

Example 2
遅延制御は,シーケンシャルブロックにて,時間的に2つの代入を分割するために使うことができる.

begin
  areg = breg;
  @(posedge clock) creg = areg; // assignment delayed until
end

Example 3
次の例は,シーケンシャルブロックとdelay制御の連携が,time-sequencedな波形を与えるためにどのように使われるかを示します.

parameter d = 50; // d declared as a parameter and
reg [7:0] r; // r declared as an 8-bit reg
begin // a waveform controlled by sequential delay
  #d r = 'h35;
  #d r = 'hE2;
  #d r = 'h00;
  #d r = 'hF7;
  #d -> end_wave;  //trigger an event called end_wave
end

9.8.2 パラレルブロック ~ Parallel blocks

パラレルブロックは,以下の特徴を有します.

  • 命令文は,並行に実行されます.
  • 各命令文の遅延時間は,ブロックに入ったシミュレーション時間に基づいて考えられます.
  • 遅延制御は,代入のためのtime-orderingを提供するために使うことができます.
  • 制御は,最後のtime-ordered命令文が実行されたときに,ブロックを抜けます.
par_block ::= (From Annex A - A.6.3)
fork [ : block_identifier { block_item_declaration } ] { statement } join
block_item_declaration ::= (From Annex A - A.2.8)
    { attribute_instance } block_reg_declaration
  | { attribute_instance } event_declaration
  | { attribute_instance } integer_declaration
  | { attribute_instance } local_parameter_declaration
  | { attribute_instance } parameter_declaration
  | { attribute_instance } real_declaration
  | { attribute_instance } realtime_declaration
  | { attribute_instance } time_declaration

fork-joinブロック中のタイミング制御は,時間内に連続して命令される必要はありません.

Example
以下のコード例は,シーケンシャルブロックの変わりに,パラレルブロックを使って,LRM 9.8.1の例3で示された定義の波形をコーディングします.reg上の波形は,勿論,どちらの実装でも同じになります.

fork
  #50 r = ’h35;
  #100 r = ’hE2;
  #150 r = ’h00;
  #200 r = ’hF7;
  #250 -> end_wave;
join

9.8.3 ブロック名 ~ Block names

シーケンシャルブロックもパラレルブロックも,beginやforkキーワードの後に,": ブロック名"を付け加えることで,名前をつけることができます.ブロックの名前付けは,いくつかの目的に役立ちます.

  • ブロックのために,ローカル変数,ローカルparameter,named eventの宣言を許容します
  • ブロックに対して,11章で述べるdisable statementのような命令文の参照を許容します.

全ての変数は,静的です.というのは,全ての変数に唯一の場所が存在し,ブロックへの入出は値の格納に影響を与えません.

All variables shall be static that is,
 a unique location exists for all variables 
 and leaving or entering blocks shall not affect the values stored in them.

ブロック名は,どのようなシミュレーション時間でも,唯一すべての変数を特定する手段を与えます。


9.8.4 開始時間と終了時間 ~ Start and finish timesシーケンシャルブロックも,手続き型ブロックも,開始時間(start time)と終了時間(finish time)の概念を持ちます.
シーケンシャルブロックにおいて,開始時間は,最初の命令文を実行するときです.終了時間は,最後の命令文を実行したときです.
パラレルブロックにおいて,開始時間は,全ての命令文に対して同じです.終了時間は,最後のtime-ordered(時間順の)命令文が実行し終わったときです.

シーケンシャルブロックとパラレルブロックは,(互いに/簡単に表現するために複雑な制御構造を許容して/高度の構造で)組み込まれることが可能です.

Sequential and parallel blocks can be embedded within each other,
 allowing complex control structures to be expressed easily and with a high degree of structure.

ブロックが互いに組み込まれるとき,ブロックの開始と終了するときのタイミングが重要です.実行は,今いるブロックが最終時間に達するまで,ブロックがかぺきに実行を完了するまでは,次のブロックへ移ってはいけません.

Example 1
以下の例は,LRM 9.8.2の例を逆順に書いた命令文を示します.これは同じ波形を提供します.

fork
  #250 -> end_wave;
  #200 r = ’hF7;
  #150 r = ’h00;
  #100 r = ’hE2;
  #50 r = ’h35;
join

Example 2
代入が2つの別のイベントが同時に起きた後に作られる時,(イベントの結合として知られています)fork-joinブロックが有用です.

begin
  fork
    @Aevent;
    @Bevent;
  join
  areg = breg;
end

2つのイベントはどのような順にでも(同じシミュレーション時間にでも)起きることができます.そして,そのfork-joinブロックは満了し,代入がなされます.
これとは対照的に,もしfork-joinブロックが begin-endブロックで,BeventがAeventよりも前に起きたならば,ブロックは次のBeventを待つでしょう.

Example 3
この例は,2つのシーケンシャルブロックを示します.いずれも,イベントが起きることを制御したときに実行されます.
なぜならば,イベント制御はfork-joinブロックの中にあり,並行して実行されます.そして,シーケンシャルブロックもまた,並行して実行することができます.

fork
  @enable_a
  begin
    #ta wa = 0;
    #ta wa = 1;
    #ta wa = 0;
  end
  @enable_b
  begin
    #tb wb = 1;
    #tb wb = 0;
    #tb wb = 1;
  end
join


9.9 構造型手続き ~ Structured procedures

全てのVerilog HDLの手続きは,以下の4命令文の1つで与えられる.

 initial construct
 always construct
Task
Function

initial構文とalways構文は,シミュレーション開始時に有効にされます.
initial構文は,一度だけ実行され,命令文が終了したときにアクティビティは終わります.
対照的に,always構文は,繰り返し実行します.
アクティビティはシミュレーションが終了したときに終わります.
どんな暗黙の実行順序も,initial構文とalways構文の間にはありません.
initial構文は,スケジュールされる必要はなく,always構文の前に実行されなければならない.
モジュール内で,定義できるinitial構文/always構文の数に制限はない.

taskとfunctionは,他の手続きで1つ以上の場所から有効にできる手続きです.taskとfunctionは,LRM 10で述べます.


9.9.1 Initial construct

initial構文の文法を以下に示す.

initial_construct ::= (From Annex A - A.6.2)
  initial statement

以下の例は,シミュレーションの開始時に変数の初期化のためのinitial構文を図示します.

initial begin
  areg = 0; // initialize a reg
  for (index = 0; index < size; index = index + 1)
    memory[index] = 0; //initialize memory word
end

他の一般的なinitial構文の使い方は,シミュレーションされる回路の主要部を刺激する手段を提供するために,一度だけ実行する記述の,波形の仕様です.

initial begin
  inputs = 'b000000; //initialize at time zero
  #10 inputs = 'b011001; // first pattern
  #10 inputs = 'b011011; // second pattern
  #10 inputs = 'b011000; // third pattern
  #10 inputs = 'b001000; // last pattern
end

9.9.2 always構文 ~ Always construct

always構文は,シミュレーション期間中は連続的に繰り返します.

always_construct ::= (From Annex A - A.6.2)
  always statement

always構文は,(その周期性により)多くのタイミング制御の様式に関連して使われるときにのみ有用です.
もしalways構文が拡張のためのシミュレーション時間の制御を持たないならば,シミュレーションのデッドロック状態を作り出すでしょう.

以下のコード,例えば,遅延ナシの無限ループを作る.

always areg = ~areg;

前述のコードにタイミング制御を提供することは,以下に示したように,潜在的に使える記述を作る.

always #half_period areg = ~areg;