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;

LRM読解(Chap.9-3)

2008/10/04Verilog::文法import

Behavioral modeling~その3


9.7 手続き型タイミング制御 ~ Procedural timing controls

Verilog HDLは,手続き型命令が現れたときに,必然的に含まれているタイミング制御の2種類を持ちます.1つ目のタイプは遅延制御で,式は,命令文に最初に遭遇したときと,命令文を実際に実行するときの間の時間遅延を与える.遅延式は,回路状態の動的な機能になりますが,時間内に,分割された命令文の実行する簡単な数でしょう.遅延制御は,スティミュラスな波形記述を与えるとき,重要な特徴です.これについてはLRM 9.7.1と9.7.7で記述します.

タイミング制御の2つ目は,イベント式です.イベント式は,ある手続き中,同時実行している手続き内で生じるシミュレーションイベントが起きるまで,命令文の実行を遅延させることができます.
シミュレーションイベントは,net上の値の変化 や 変数の変化(暗黙のうちのイベント),(明白な)他の手続きからトリガされる明示的な名前つきイベントが起きたときとなるでしょう.
より多くは,イベント制御は,クロック信号の立ち上がりまたは立下りエッヂとなります.イベント制御は LRM 9.7.2から LRM 9.7.7にかけて議論されます.

今までのところ遭遇している手続き型命令文の全ては,シミュレーションを進めないで実行します.

シミュレーション時間は,以下の3つの方法の1つで進められます.

  • 遅延制御,シンボル'#'で紹介されます.
  • イベント制御,シンボル'@'で紹介されます.
  • wait文,イベント制御とwhileループの組み合わせのように機能します.

Syntax

delay_control ::= (From Annex A - A.6.5)
    # delay_value
  | # ( mintypmax_expression )

delay_or_event_control ::=
    delay_control
  | event_control
  | repeat ( expression ) event_control

event_control ::=
    @ event_identifier
  | @ ( event_expression )
  | @*
  | @ (*)

event_expression ::=
    expression
  | hierarchical_identifier
  | posedge expression
  | negedge expression
  | event_expression or event_expression
  | event_expression , event_expression

gateとnetの遅延もまた,6章で議論したようにシミュレーション時間を進めます.次節では,3つの手続き型タイミング制御方法について議論します.


9.7.1 遅延制御 ~ Delay control

遅延制御に続く手続き文は,与えられた遅延に先立って遅延制御を行う手続き文に関して,実行するのを遅らされます.

  • 遅延式が不定またはハイインピーダンス値として評価された場合は,ゼロ遅延のように解釈されるでしょう.
  • 遅延式が負の値と評価された場合は,時間変数(time variable)と同じサイズの符号無し整数(unsigned int)の2の補数と解釈されるでしょう.

与えられたパラメータは,遅延式中で許されます.式が再評価される場合には,SDFアノテーションにより上書きされます.

例1
以下の例は,10時間単位だけ代入の実行を遅延します.The following example delays the execution of the assignment by 10 time units:

#10 rega = regb;

例2
次の3つの例は,サイン('#')に続く式を与えます.代入処理は,式の値で与えられたシミュレーション時間の間だけ,遅延されます.Execution of the assignment is delayed by the amount of simulation time specified by the value of the expression.

#d rega = regb; // d is defined as a parameter
#((d+e)/2) rega = regb;// delay is average of d and e
#regr regr = regr + 1; // delay is the value in regr

9.7.2 イベント制御 ~ Event control

手続き文の実行は,net上の値の変化 や 変数の変化(暗黙のうちのイベント),(明白な)他の手続きからトリガされる明示的な名前つきイベントが起きたときに同期されるでしょう.
The value changes on nets and variable can be used as events to trigger the execution of a statement. netや変数の値の変化は,命令文の実行トリガのイベントのように使われます.This is known as detecting an implicit event.これは,暗黙のイベント検出として知られます.The event can also be based on the direction of the change that is, towards the value 1 ( posedge) or towards the value 0 (negedge).イベントは,変化の方向(1への変化(posedge)か0への変化(negedge))を元にも使われます.The behavior of posedge and negedge event is shown in Table 43 and can be described as follows: posedgeとnegedgeイベントのビヘイビアは,次の表に示され,以下のように記せます.

  • negedgeは,1からx/z/0,x/zから0への変化で検出されます.
  • posedgeは,0からx/z/1,x/zから1への変化で検出されます.

from|to 0 1 x z
0No edgeposedgeposedgeposedge
1negedgeNo edgenegedgenegedge
xnegedgeposedgeNo edgeNo edge
znegedgeposedgeNo edgeNo edge

もし,式が1bitより長い結果を評価するならば,エッヂの遷移は,結果のLSB(最下位ビット)において検出されるでしょう.式の結果のLSBの値の変化を除いた,どのオペランドの値の変化もエッヂの検出はされない.


例:
The following example shows illustrations of edge-controlled statements.以下の例は,エッヂ制御分を図示します.

@r rega = regb; // レジスタrのどのような変化にでも制御される
@(posedge clock) rega = regb; // clockの立上がりエッヂに制御される
forever @(negedge clock) rega = regb; // 立下りエッヂに制御される

9.7.3 名前つきイベント ~ Named events

net型とvariable型に加えて,event型と呼ばれる新しいデータ型を宣言することができる.event data型の識別子の宣言は,named eventと呼ばれる.

LRM 9.7.1で議論したイベント制御のようなやり方と同様に,手続き命令文の実行を制御するために,イベント式で使うことができる.

named eventsは,手続きから起こすことができます.これは,ほかの手続きにおける,複数の動作を可能にすることの制御を許容します.
イベント名は,使用する前に明示的に宣言されます.文法を以下に示します.

event_declaration ::= (From Annex A - A.2.1.3)
  event list_of_event_identifiers ;

list_of_event_identifiers ::= (From Annex A - A.2.3)
  event_identifier [ dimension { dimension }]
  { , event_identifier [ dimension { dimension }] }

dimension ::= (From Annex A - A.2.5)
  [ dimension_constant_expression : dimension_constant_expression ]

イベントは,データを保持しません.named eventの特徴を以下に列挙します.

  • 特定のいつでも起こすことができる.
  • 時間間隔を持たない.(It has no time duration)
  • 説明したイベント制御構文を用いて,発生を認識できます。

宣言されたeventは,以下の構文のイベントトリガ命令文の活性化(actrivation)により,起こされます.eventは,イベント制御式中のevent arratのindexの変化によっては,起こされません.(どゆこと?)

An event is not made to occur by changing the index of an event array in an event control expression.
event_trigger ::= (From Annex A - A.6.5)
  -> hierarchical_event_identifier ;

イベント制御命令文(例えば,@trig rega = regb;)は,手続きに含まれるシミュレーションを,ほかの手続きが特定のイベントトリガ命令文(例えば, -> trig)を実行するまで,待たせる.

named eventとイベント制御は,強力で効果的な,複数同時実行されるプロセス間の同期やコミュニケーション記述を与える.

この基本的な例は,回路がイベントを待っている間,定期的に明示的なイベントが起きたことを通知することによって同期回路の同期制御をするような小さな波形クロック生成器です.


9.7.4 イベント 'or'演算子 ~ Event or operator

The logical or of any number of events
 can be expressed such that
  the occurrence of any one of the events triggers the execution of the procedural statement that follows it.

わがらん('A`

キーワード'OR'かコンマ文字','が,イベント論理OR演算子として使われます.この組み合わせは,同じイベント式で用いることができます.コンマ分割のセンシビリティリストは,OR分割のセンシビリティリストと同値です.


次の二つの例は,それぞれ2つと3つのイベント論理ORを示します.

@(trig or enable) rega = regb; // trig か enable によって制御される.
@(posedge clk_a or posedge clk_b or trig) rega = regb;

以下の例は,イベント論理OR演算子として,コンマを使用することを示します.

always @(a, b, c, d, e)
always @(posedge clk, negedge rstn)
always @(a or b, c, d or e)

9.7.5 暗黙的な イベント式リスト ~ Implicit event_expression list

The event_expression list of an event control is a common source of bugs in RTL simulations.イベント制御のイベント式リストは,RTLシミュレーションにおけるバグの元凶です.

Users tend to forget to add some of the nets or variables read in the timing control statement.ユーザは,タイミング制御文中に読み出すnetやvariableを追加することを忘れることに応対する(直面する?)

This is often found when comparing RTL and gate level versions of a design.これは,しばしばRTLとゲートレベル設計との比較で見つけられる.

The implicit event_expression, @*, is a convenient shorthand that eliminates these problems by adding all nets and variables which are read by the statement (which can be a statement group) of a procedural_timing_control_statement to the event_expression.暗黙的なイベント式(@*)は,手続きタイミング制御命令文の命令文(命令文グループでも良い)によって読み出される,全てのnet/variableを追加することによる問題を省略するための,便利な略記です.


命令文中に現れる全てのnet/variable識別子は,自動的に以下の式以外がイベント式に追加されます.

  • wait式,event式中にのみ現れる識別子
  • 代入の左辺のレジスタ(reg_lvalue)中にのみ現れる,hierarchical_reg_identifierのような識別子

代入式の右辺,functionやtask呼び出し,case/状態式に現れるnet/variableは,すべてこのルールに当てはまります.


例1

always @(*) // equivalent to @(a or b or c or d or f)
  y = (a & b) | (c & d) | myfunction(f);

例2

always @* begin // equivalent to @(a or b or c or d or tmp1 or tmp2)
  tmp1 = a & b;
  tmp2 = c & d;
  y = tmp1 | tmp2;
end

例3

always @* begin // equivalent to @(b)
  @(i) kid = b; // i is not added to @*
end

例4

always @* begin // equivalent to @(a or b or c or d)
  x = a ^ b;
  @* // equivalent to @(c or d)
    x = c ^ d;
end

9.7.6 レベルセンシティブイベント制御 ~ Level-sensitive event control

手続き命令文の実行もまた,状態がtrueになるまで遅延されることができます.これは,特別な形式のイベントコントロールである,wait命令文を使うことに優れています.

wait命令文の本質は,('@'文字で与えられる)エッヂセンシティブな基本イベント制御に反対である,レベルセンシティブです.
wait命令文は,状態を評価し,falseであれば,wait命令文に続く手続き命令は,続ける前に,状態がtrueになるまで,ブロックされ,とどまります.

wait命令文は以下の書式を持ちます.

wait_statement ::= (From Annex A - A.6.5)
  wait ( expression ) statement_or_null


以下の例は,レベルセンシティブイベントコントロールを果たすためのwait命令文の使い方を示す.

begin
  wait (!enable) #10 a = b;
  #10 c = d;
end

blockに入ったとき,enableの値が1ならば,enableの値が0に変化するまで,wait命令文は次の命令文(#10 a = b;)の評価を遅延します.
blockに入ったとき,enableがすでに 0であったならば,10の遅延の後に代入(a = b;)は評価され,追加の遅延は起きません.


9.7.7 内部代入タイミング制御 ~ Intra-assignment timing controls

前述したdelay/event制御構造は,命令文の前置きをして,その実行を遅延させます.
対照的に,intra-assignment delayとevent controlsは,代入文と異なる方法のアクティビティの流れを修正することを含みます.

この節では,intra-assignmentのタイミング制御と,intra-assignment delayで使えるrepeatタイミング制御の目的について記す.
intra-assignment delayまたはイベント制御は,新しい値を左辺に代入することを遅らせます.しかし,右辺式は,遅延の後の変わりに,遅延の前に評価されます.
intra-assignment delayとイベント制御のの構文を以下に示す.

blocking_assignment ::= (From Annex A - A.6.2)
  variable_lvalue = [ delay_or_event_control ] expression

nonblocking_assignment ::=
  variable_lvalue <= [ delay_or_event_control ] expression

delay_control ::= (From Annex A - A.6.5)
    # delay_value
  | # ( mintypmax_expression )

delay_or_event_control ::=
    delay_control
  | event_control
  | repeat ( expression ) event_control

event_control ::=
    @ event_identifier
  | @ ( event_expression )
  | @*
  | @ (*)

event_expression ::=
    expression
  | hierarchical_identifier
  | posedge expression
  | negedge expression
  | event_expression or event_expression
  | event_expression , event_expression

intra-assignment delayとイベント制御は,ブロッキング代入とノンブロッキング代入の双方に適用可能です.
イベント式は,1bitの値として結果を得ます.
repeatイベント制御は,与えられたイベントの発生回数のintra-assignment delayにより与えられます.
もし,繰り返し回数リテラルまたは繰り返し数を保持したsignedのreg型が,評価時に0以下である場合,まるでrepeat構文が無いかのように代入処理がおきます.
# 例と本文が違うような... 原文を引用しておきます. 翻訳が間違ってる?

If the repeat count literal, or signed reg holding the repeat count,
 is less than or equal to 0 at the time of evaluation,
  the assignment occurs as if there is no repeat construct.

Examples:

repeat (-3) @ (event_expression)
  // will not execute event_expression. イベント式は実行されません
repeat (a) @ (event_expression)
  // if a is assigned -3 it will execute the event_expression. aに-3が代入されていれば,イベント式は実行されます.
  // if a is declared as an unsigned reg but not if it is signed. もしaがunsigned regで宣言されていれば,の話.

この構造は,イベントがクロック信号のカウントに同期する必要がある時に便利です.

Examples:
以下の表は,intra-assignmentを使わずに,同じタイミング効果を成就できるコードを示すことで,intra-assignmentタイミング制御の原理を図解しています.

Intra-assignment timing control
With intra-assignment constructWithout intra-assignment construct
a = #5 b;begin<BR>temp = b;<BR>#5 a = temp;<BR>end
a = @(posedge clk) b;begin<BR>temp = b;<BR>@(posedge clk) a = temp;<BR>end
a = repeat(3) @(posedge clk) b;begin<BR>temp = b;<BR>@(posedge clk);<BR>@(posedge clk);<BR>@(posedge clk) a = temp;<BR>end

次の3つの例は,fork-joinビヘイビア構造を使います.forkとjoinの間の全ての命令文は,同時に実行します.この構造は,LRM 9.8.2で,より詳しく記述されます.

以下の例は,intra-assignmentタイミング制御を使うことで予防できるレースコンディションを示します.

fork
  #5 a = b;
  #5 b = a;
join

この例のコードは,同じシミュレーション時間において,aとbの双方の値を,参照・設定します.次の例で用いられるタイミング制御のintra-assignment様式は,このレースコンディションを防げます.

fork // data swap
  a = #5 b;
  b = #5 a;
join

intra-assignmentタイミング制御は,動きます.というのも,intra-assignment遅延は,aとbの値を遅延前に評価させて,遅延後に代入させるからです.

intra-assignmentタイミング制御の実装をしている,多くの既存ツールは,各右辺式の評価において,一時的な記憶領域を使います.

イベント待ちであるintra-assignmentもまた,有効です.以下の例において,右辺式は,代入文にエンカウントしたときに評価されますが,代入はクロック信号の立ち上がりエッヂまで遅延されます.

fork // data shift
  a = @(posedge clk) b;
  b = @(posedge clk) c;
join

以下は,ノンブロッキング代入のintra-assignment遅延のようなrepeatイベント制御の例です.

a <= repeat(5) @(posedge clk) data;

Figure 31 illustrates the activities that result from this repeat event control.

(図省略)この例において,dataの値は,代入がエンカウントされたときに評価されます.clkの立ち上がりエッヂの5回発生後に,aはdataの値を代入されます.以下は,手続き代入のintra-assignment遅延のような repeatイベント制御の例です.

a = repeat(num) @(clk) data;

この例では,dataの値は,代入が演歌ぬとされたときに評価されます.clkの遷移回数がnumの値と一致した後,aはdataの値を代入される.以下は,イベント発生回数と,カウントされたイベントの両方を演算に含んだrepeatイベント制御の例です.

a <= repeat(a+b) @(posedge phi1 or negedge phi2) data;

In this example,この例において,dataの値は代入にエンカウントされたときに評価される.phi1の立ち上がりエッヂとphi2の立下りエッヂの総和が,aとbの和と等しくなった後,aはdataの値を代入される.
もし,phi1の立ち上がりエッヂとphi2の立下りエッヂとが,同じシミュレーション時間に生じても,それぞれ分けて検出されます.

LRM読解(Chap.9-2 Behavioral/case,loop)

2008/10/04Verilog::文法import

Behavioral modeling~その2



9.5 case文 ~ Case statement

case文は,式が多くの他の式の1つとマッチするか,分岐するかどうかに関係なくテストする,複数判断命令文です.

case_statement ::= (From Annex A - A.6.7)
    case ( expression )
      case_item { case_item } endcase
  | casez ( expression )
      case_item { case_item } endcase
  | casex ( expression )
      case_item { case_item } endcase

case_item ::=
    expression { , expression } : statement_or_null
  | default [ : ] statement_or_null

function_case_statement ::=
    case ( expression )
      function_case_item { function_case_item } endcase
  | casez ( expression )
      function_case_item { function_case_item } endcase
  | casex ( expression )
      function_case_item { function_case_item } endcase

function_case_item ::=
    expression { , expression } : function_statement_or_null
  | default [ : ] function_statement_or_null

default文は,オプションです.1つのcase文で複数のdefault文を使うのは不当です.
The case expression and the case item expression can be computed at runtime; neither expression is required to be a constant expression. case式とcase item式は,実行時に計算されます.どちらの式も,定数式になるには必要ではありません.

(例)

case-item式は,与えられた順に性格に,評価・比較されます.
線形探索において,case item式のひとつが,丸括弧(parentheses)で与えられたcase式にマッチするならば,case-itemに対応する命令文が実行されます.
全ての比較が失敗し,default-itemが与えられているならば,default-itemの命令文が実行されます.
もし,default文が無くて,全ての比較が失敗したならば,どのcase-item文も実行されません.構文は別として,case文はif-else-if構造に比べて2つの重要な違いがあります.

  • if-else-if構造の状態式のほうが,case文のように1つの式をその他と比較するよりも一般的(general)です.
  • case文は,式中の'x'や'z'が存在する時に,決定的な結果を提供します.

case式の比較において,比較は,各ビットが値'0', '1', 'x', 'z'に関して厳密にマッチするときにのみ成功します.
結果として,case文中の式を与えることには,注意が必要です.
全ての式のbit長は,正確なbit-wiseマッチングができるように,等しくなるでしょう.
全てのcase-item式の長さと丸括弧のcase式は,case式とcase-item式の最長のものと等しくするものとします.


注意
'x'と'z'のデフォルトの長さは,integerのデフォルト長と同じです.

'x'と'z'の値をハンドリングするようなcase式比較を提供する理由は,そのような値を検出し,それらの(値の)存在によって発生する悲観主義(pessimism)を減少させるためのメカニズムを提供するためです.


9.5.1 "don't care"ありのcase文 ~ Case statement with don't-cares

2つの種類の異なるcase文は,case比較演算子中のdon't case状態のハンドリングを提供する.1つは,ハイインピーダンス(z)をdon't careとして扱い,他方はハイインピーダンス(z)と不定(x)とをdon't careとして扱う.
これらのcase文は,慣例的なcase文と同じように使うことができる.しかし,それら(z,zxをdon't careとして扱うcase文)はそれぞれcasezとcasexで始まる.
case式かcase itemのどんなbitの中のdon't care値(casezではz, casexではz/x)は,比較演算時にdon't care状態として扱われ,考慮されないでしょう.
case式のdon't care状態は,どんなときでも比較すべきビットを動的に制御することに使えるでしょう.
字句構文は,case文中のzをクエスチョンマーク'?'に置き換えて使うことができる.これは,case文中でdon't care bitを与えるために,便利な書式を提供します.

例1. casez文の例を以下に示す.
殿タスクを呼ぶべきかをMSBの値が選択する,命令デコーダのデモです.irのMSBが1ならば,irのほかのbitに関係なくtask instruction1が呼ばれます.

reg [7:0] ir;
casez (ir)
  8’b1???????: instruction1(ir);
  8’b01??????: instruction2(ir);
  8’b00010???: instruction3(ir);
  8’b000001??: instruction4(ir);
endcase

例2. casex文の例を以下に示す.
この例の場合,r=8'b01100110であれば,task stat2が呼ばれます.(不定値演算は不定のままになりそうだけれど.)

reg [7:0] r, mask;
mask = 8’bx0x0x0x0;
casex (r ^ mask)
  8’b001100xx: stat1;
  8’b1100xx00: stat2;
  8’b00xx0011: stat3;
  8’bxx010100: stat4;
endcase

01100110 x0x0x0x0

  • 0-1-0-=
  • 1-0-=-0
  • 0-=-0-1
  • =-1-1-0

# stat1,3がぶつかりそうな気がするのだけれど.8'x0x1x0x1 のとき,どっちにもあたるよな?


9.5.2 case文での定数式 ~ Constant expression in case statement

定数式をcase式として使えます.定数式の値は,case item式に対して比較されます.


以下の例は,3bit priority encoderのモデリングを例示します.

reg [2:0] encode ;
case (1)
  encode[2] : $display(“Select Line 2”) ;
  encode[1] : $display(“Select Line 1”) ;
  encode[0] : $display(“Select Line 0”) ;
  default $display(“Error: One of the bits expected ON”);
endcase

Note注意
case式は定数式(1)です.case itemは,式(bit-select)で,定数式に対して一致が比較されます.


9.6 ループ構文 ~ Looping statements

ループ文として4種類あります(下表に示す).これらの命令文は,0,1,それ以上の命令の実行を制御する手段をを提供する.

forever命令文を継続的に実行する.
repeat固定回数だけ命令文を実行する.もし,式が不定かハイインピーダンスと評価されたなら,ゼロとして扱われ,命令文は実行されない.
while式がfalseになるまで,命令文を実行する.もし式がfalseで始まるならば,命令文はまったく実行されません.
for{以下のように3段階の手順で,関連する命令の実行を制御します.

a) 一般的には,ループの実行回数を制御する変数の初期化に使われる代入を実行します.b) 式評価し,結果がゼロであれば forループを終了し,ゼロでなければ関係する命令を実行してstep cへ進む.もし式が不定またはハイインピーダンスと評価されれば,ゼロとして扱う(ループを抜ける).c) 通常,ループ制御変数の値を更新するための代入に用いる.その後,step bへ戻る.}|

function_loop_statement ::= (From Annex A - A.6.8)
    forever function_statement
  | repeat ( expression ) function_statement
  | while ( expression ) function_statement
  | for ( variable_assignment ; expression ; variable_assignment ) function_statement

loop_statement ::=
    forever statement
  | repeat ( expression ) statement
  | while ( expression ) statement
  | for ( variable_assignment ; expression ; variable_assignment ) statement

The rest of this clause presents examples for three of the looping statements.この節の残りでは,ループ文の3つの例を挙げます.The forever loop should be used /in conjunction with/ the timing controls or the disable statement, therefore, this example is presented in 9.7.2.

foreverループは,タイミング制御かdisable命令と同時に使われます.それ故,その例は9.7.2で紹介します.

例1
: Repeat文: 以下repeatループの例は,addとshift演算が乗算器を実装する例です.

parameter size = 8, longsize = 16;
reg [size:1] opa, opb;
reg [longsize:1] result;

begin : mult
  reg [longsize:1] shift_opa, shift_opb;
  shift_opa = opa;
  shift_opb = opb;
  result = 0;

  repeat (size) begin
    if (shift_opb[1])
      result = result + shift_opa;
    shift_opa = shift_opa << 1;
    shift_opb = shift_opb >> 1;
  end
end

例2
While文: 以下の例は,rega内の論理1の値を数えます.

begin : count1s
  reg [7:0] tempreg;
  count = 0;
  tempreg = rega;
  while (tempreg) begin
    if (tempreg[0])
      count = count + 1;
    tempreg = tempreg >> 1;
  end
end

例3
For 文: for命令は,whileループを基にした下記の擬似命令のような同じ結果を成し遂げる.

begin
  initial_assignment;
  while (condition) begin
    statement
    step_assignment;
  end
end

forループは,以下に示すような擬似命令で,たった2行を使うだけでこのロジックを実装します.

for (initial_assignment; condition; step_assignment)
  statement

LRM読解(Chap.9-1 Behavioral modeling)

2008/10/04Verilog::文法import

Behavioral modeling~その1

今までのところ導入されている言語構造は,ハードウェアが比較的詳細なレベルで説明されるのを許容します.ロジックゲートと常時代入による回路モデリングは,モデル化される回路の論理構造をとてもきっちりと反映します.しかし,この構文は,システムの複雑なハイレベルの様相/方向について説明するのに必要な抽象化能力を提供しません.

この章で記される手続き型構文は,マイクロプロセッサを記述したり,複雑なタイミングチェックを実装するような問題に取り組むのに,とても適している.

この章は,Verilog HDLで,ビヘイビア文のいくらかの種類の文脈を提供するビヘイビアモデルの概要から始まります.



9.1 Behavioral model overview

Verilogビヘイビアモデルは,シミュレーションを制御したり,前述したデータ型の変数の値を操作する,手続き文を含みます.この命令文は,手続きに含まれています.各手続きは,それに関する能動的な(activity)フローを持ちます.

その活動(activity)は,制御構文 initial と always で始まります.それぞれのinitial文やalways文は,分割された能動的な(activity)フローを始めます.全ての能動的な(activity)フローは,ハードウェアで固有の並行性をモデル化することにおいて同時発生的です.
この構造は LRM9.9で正式に記述されます.以下の例は,完全なVerilgoビヘイビアモデルをあらわします.

module behave;
reg [1:0] a, b;
  initial begin
    a = ’b1;
    b = ’b0;
  end

  always begin
    #50 a = ~a;
  end
  always begin
    #100 b = ~b;
  end
endmodule

このモデルのシミュレーションにおいて,initial文とalways文によって記述された全てのフローは,シミュレーション時刻0から開始されます.
initial文は一度だけ実行し,always文は繰り返し実行します.

このモデルでは,シミュレーション時刻0において,reg変数 a,b は,それぞれ1,0に初期化されます.
initial文は,それで完了し,このシミュレーション実行中は再び実行しません.このinitial文は,begin - end block命令文(シーケンシャルブロック(sequential block)とも呼ばれます)を含みます.
begin-end block内では,最初にaが初期化され,続いてbが初期化されます.

always文も時刻0に開始されますが,変数の値は,遅延制御で与えられた時間('#'で示される)が経過するまで変化しません.
したがって,reg aは50単位時間後に反転し,reg bは100単位時間後に反転する.always文は繰り返すので,このモデルは2つの矩形波を提供するでしょう.
reg aは100単位時間周期でトグルし,reg bは200単位時間周期でトグルします.2つのalways文は,全体のシミュレーション走行の間中,並行に続きます.



9.2 Procedural assignments

As described in Clause 6, 6節で述べたように,手続き型代入は,以下のデータ型を更新するのに用いられる.

  • reg
  • integer
  • time
  • real
  • realtime
  • memory

手続き型代入と常時代入の間には,以下のようにとても大きな違いがあります.

常時代入は,netを駆動し,評価され,入力オペランドの値が変わらないときでも更新されます.
手続き型代入は,それら(代入文?)を取り囲む手続き上の流れの制御下で,変数の値を更新する.

手続き型代入の右辺は,値として評価されるどのような式でもなれる.左辺は,右辺からの代入を受け取る変数となるでしょう.手続き型代入の左辺は,以下の様式をとることができます.

|*RHS-type |* LHS constraint? |
|reg, integer, real, realtime, or time data type | これらのデータ型の1つの名前参照への代入 |
|Bit-select of a reg, integer, or time data type | その他の触らないビットを残して,1ビットへの代入	|
|Part-select of a reg, integer, or time data type| 残りの触らないビットを残して,1異常の連続したビットの部分選択 |
|Memory word | 	memoryの1ワード |
|Concatenation of any of the above | 前の4つのフォームの,いずれかの連結を指定できます.(左辺は)連結した一部なので,ので,右辺の式の結果を分割し,分割した部分を代入します.|

注意:
右辺のビット長が左辺のビット長より短い場合,右辺が符号あり(LRM 4.5参照)であれば,左辺の大きさは符号拡張されるでしょう.

Verilog HDLは,以下の2種類の手続き型代入文を有します.

  • ブロッキング代入文
  • ノンブロッキング代入文

ブロッキング・ノンブロッキング代入文は,シーケンシャルブロックにおいて異なる手続き上のフローを与えます.


9.2.1 Blocking procedural assignments

ブロッキング代入文は,シーケンシャルブロック(9.8.1参照)中の後続の命令文を実行する前に,処理されます.
ブロッキング代入文は,パラレルブロック(9.8.2参照)中では,後続の命令文を実行するのは妨げない.

blocking_assignment ::= (From Annex A - A.6.2)
  variable_lvalue = [ delay_or_event_control ] expression

delay_control ::= (From Annex A - A.6.5)
  # delay_value
  | # ( mintypmax_expression )

delay_or_event_control ::=
  delay_control
  | event_control
  | repeat ( expression ) event_control

event_control ::=
  @ event_identifier
  | @ ( event_expression )
  | @*
  | @ (*)

event_expression ::=
  expression
  | hierarchical_identifier
  | posedge expression
  | negedge expression
  | event_expression or event_expression
  | event_expression , event_expression

variable_lvalue ::= (From Annex A - A.8.5)
  hierarchical_variable_identifier
  | hierarchical_variable_identifier [ expression ] { [ expression ] }
  | hierarchical_variable_identifier [ expression ] { [ expression ] } [ range_expression ]
  | hierarchical_variable_identifier [ range_expression ]
  | variable_concatenation

この文法について;

reg_lvalue手続き型代入文に使えるデータ型
'='代入演算子
delay_or_event_control補助的な,内部代入(intra-assignment)タイミング制御
expression左辺に代入される右辺の値

制御(delay_or_event_control)は,delay_control(例えば "#6") またはevent_control(例えば "@(posedge clk)")をとり得ます.
もし,reg_lvalueが評価を要するならば,内部代入(intra-assignment)タイミング制御に与えられた時間に評価されます.
ブロッキング手続き型代入で用いられる'='演算子は,手続き型常時代入と常時代入にも使われます.


9.2.2 The non blocking procedural assignment

ノンブロッキング手続き代入は,手続き的なフローを妨げることなく,代入処理のスケジューリングを許容する.
ノンブロッキング手続き代入文は,同じ時間ステップに代入されるあらゆる変数が,互いに独立に,または順序に関係ないときに用いる.

nonblocking_assignment ::= (From Annex A - A.6.2)
  variable_lvalue <= [ delay_or_event_control ] expression

delay_control ::= (From Annex A - A.6.5)
    # delay_value
  | # ( mintypmax_expression )

delay_or_event_control ::=
    delay_control
  | event_control
  | repeat ( expression ) event_control

event_control ::=
    @ event_identifier
  | @ ( event_expression )
  | @*
  | @ (*)

event_expression ::=
    expression
  | hierarchical_identifier
  | posedge expression
  | negedge expression
  | event_expression or event_expression
  | event_expression , event_expression

variable_lvalue ::= (From Annex A - A.8.5)
    hierarchical_variable_identifier
  | hierarchical_variable_identifier [ expression ] { [ expression ] }
  | hierarchical_variable_identifier [ expression ] { [ expression ] } [ range_expression ]
  | hierarchical_variable_identifier [ range_expression ]
  | variable_concatenation

In this syntax

reg_lvalue手続き型代入文に使えるデータ型
'<='ノンブロッキング代入演算子
delay_or_event_control補助的な,内部代入(intra-assignment)タイミング制御
expression左辺に代入される右辺の値

もし,reg_lvalue が評価を要するならば,右辺の式が評価されるのと同じ時刻に評価されるでしょう.
もし,タイミング制御が支持されていなければ,reg_lvalueと右辺の式の評価順序は未定義です.

ノンブロッキング代入演算子は,関係演算子"小なりまたは等しい(<=)"と同じです.解釈は "<="が現れる文脈から決められるものとします.
式中に "<="が使われているとき,関係演算子と解釈され,ノンブロッキング手続き代入で使われているときは,代入演算子と解釈されるでしょう.

ノンブロッキング手続き代入は,5節で議論したように2段階で評価されるでしょう.
2つのステップについては,以下の例中に示します.

(例を省略します)



9.3 Procedural continuous assignments

assign文 や force文を使った 手続き型常時代入は,変数かネットを連続的に駆動する式を許容する手続き命令文です.

net_assignment ::= (From Annex A - A.6.1)
  net_lvalue = expression

procedural_continuous_assignments ::= (From Annex A - A.6.2)
    assign variable_assignment
  | deassign variable_lvalue
  | force variable_assignment
  | force net_assignment
  | release variable_lvalue
  | release net_lvalue

variable_assignment ::= (From Annex A - A.6.3)
  variable_lvalue = expression

net_lvalue ::= (From Annex A - A.8.5)
    hierarchical_net_identifier
  | hierarchical_net_identifier [ constant_expression ] { [ constant_expression ] }
  | hierarchical_net_identifier [ constant_expression ] { [ constant_expression ] } [ constant_range_expression ]
  | hierarchical_net_identifier [ constant_range_expression ]
  | net_concatenation

variable_lvalue ::=
    hierarchical_variable_identifier
  | hierarchical_variable_identifier [ expression ] { [ expression ] }
  | hierarchical_variable_identifier [ expression ] { [ expression ] } [ range_expression ]
  | hierarchical_variable_identifier [ range_expression ]
  | variable_concatenation

assign文の式の左辺は,変数参照か,変数の連結になるでしょう.メモリの1ワード(配列参照) や ビット選択 や 変数の部分選択にはならないでしょう.

対照的に,force文の代入式の左辺は,変数参照かネット参照になりえます.前述の連結にもできます.
ヴェクタ変数の,ビットセレクトや部分選択は許可されません.


9.3.1 The assign and deassign procedural statements

assign 手続き型常時代入分は,全ての変数への手続き型代入を上書きします.deassign手続き文は,変数への手続き型常時代入を終わるでしょう.変数の値は,手続き型代入または手続き型常時代入によってregに新しい値が代入されるまで同じ値を残すでしょう.

assignとdeassign手続き文は,例えば,エッジトリガ型D-FFの非同期クリア・プリセットのモデリングを許容します.というのも,クリアまたはプリセットがアクティブになったときに,クロックを抑制します.
キーワード"assign"が,すでに手続き型常時代入されている変数に適用されるならば,この新しい手続き型常時代入は,新しい手続き型常時代入を作る前に,変数のdeassignを行うでしょう.

以下の例は,プリセット・クリアつきD-FFのビヘイビア記述中での,assign文とdeassign文の使い方を示します.

module dff (q, d, clear, preset, clock);
output q;
input d, clear, preset, clock;
reg q;
  always @(clear or preset)
    if (!clear)
      assign q = 0;
    else if (!preset)
      assign q = 1;
    else
      deassign q;

  always @(posedge clock)
    q = d;
endmodule

clear または preset がlowならば,出力qは固有の固定値を維持し,クロックの立ち上がりエッジは qに影響を与えない.
clear と preset のどちらも highのときには,qはdeassignされます.


9.3.2 The force and release procedural statements

他の手続き型常時代入の様式は,force/release手続き命令文で提供されます.
これらの命令文は,assign-deassignの組み合わせと同様の効果を持ちますが,force文はネット型に対しても変数と同様に適用することができます.
代入式の左辺は,以下とすることができる.

  • 変数
  • ネット型
  • ネット型のヴェクタのビット選択(選択域は固定)
  • ネット型のヴェクタの部分選択(選択域は固定)
  • 連結

以下はできない.

  • メモリの1ワード(配列参照)
  • 変数型のヴェクタのビット選択・部分選択

変数に対するforce文は,release手続き文が実行されるまでは,変数で行われる手続き代入または手続き常時代入を上書きするでしょう.release手続き命令が実行された後,その変数は直ちに値を変えないでしょう.(ネット型であるかのように,手続き型常時代入として代入される)force文で与えられた値は,その変数で手続き型常時代入が有効にならないケースを除いて,次の手続き型代入が行われるまでは,変数として扱われるでしょう.
net型でのforce手続き命令文は,release手続き型命令文が実行されるまでは,すべてのゲート出力・module出力・常時代入の駆動を上書き*1します.
アクティブな手続き型常時接続を持つ変数を開放することは,その代入を再接続することになるでしょう.

module test;
  reg a, b, c, d;
  wire e;
  and and1 (e, a, b, c);
  initial begin
    $monitor("%d d=%b,e=%b", $stime, d, e);
    assign d = a & b & c;
    a = 1;
    b = 0;
    c = 1;

    #10;
    force d = (a | b | c);
    force e = (a | b | c);
    #10 $stop;
    release d;
    release e;

    #10 $finish;
  end
endmodule

 Results:
   0 d=0,e=0
   10 d=1,e=1
   20 d=0,e=0

この例において,ANDゲートインスタンス 'and1'は,foce手続き文によってORゲートに修正されています.その手続き文は,強制的にその出力値を論理和入力の値にして,論理和のassign手続き命令文のように,論理積のassign手続き命令文を書き換えます.

手続き型常時接続代入またはforce文の右辺は,式になりえます.これは常時代入のように取り扱われます.というのは,何か右辺の値が変わるならば,assignまたはforceが有効な間,代入は再評価されるものとします.例えば,

force a = b + f(c) ;

このように,bまたはcが変化するならば,aは新しい式'b+f(c)'の値に強制されるでしょう.



*1 : 元の信号接続を断って,force接続のみ有効にします.

9.4 条件文 ~ Conditional statement

条件文(もしくはif-else文)は,命令文を実行するかどうかを判断するようなことに用います.一般的なSyntaxをいかに示します.

conditional_statement ::= (From Annex A - A.6.6)
  if ( expression )
    statement_or_null [ else statement_or_null ]
  | if_else_if_statement

  function_conditional_statement ::= (From Annex A - A.6.6)
    if ( expression ) function_statement_or_null
    [ else function_statement_or_null ]
  | function_if_else_if_statement

式の評価が真(true)(これは,非ゼロの値を持つことを意味します)であれば,最初の命令文が実行されます.
式の評価が偽(faluse)(これは,ゼロもしくは'x','z'を持つことを意味します),最初の命令文は実行されません.もし,else文があり,式がfalseであれば,else文が実行されます.

if式の数値がゼロになるかどうかをテストするので,ある一定のショートカットが可能です(短縮記述できる,の意).例えば,以下の2つの式は同じ論理です.

if (expression)
if (expression != 0)

if-elseのelse部分はオプションなので,elseが入れ子にされたifシーケンスから省略されるとき,混乱するでしょう.これは,常に直前のelse文を欠いたif文と結びつくelseによって解決されます.
以下の例において,else文はインデントで示したように,内側のifといきます.

if (index > 0)
  if (rega > regb)
    result = rega;
  else // else applies to preceding if
    result = regb;

もし,前述の結びつきが期待するものでなければ,以下に示すように,期待する結びつきを強制するために,begin-endブロック構文を使うべきです.

if (index > 0) begin
  if (rega > regb)
    result = rega;
end
else result = regb;

9.4.1 If-else-if construct

if_else_if_statement ::= (From Annex A - A.6.6)
  if ( expression ) statement_or_null
  { else if ( expression ) statement_or_null }
  [ else statement_or_null ]

function_if_else_if_statement ::= (From Annex A - A.6.6)
  if ( expression ) function_statement_or_null
  { else if ( expression ) function_statement_or_null }
  [ else function_statement_or_null ]

このif-else-if構造として知られているif文のシーケンスは,複数の判断を記述するもっとも一般的な方法です.式は順番に評価され,いずれかの式が真であれば,それに対応した命令文が実行されます.そして,その後に全体のチェーンを終了します.
各命令文は,1行命令かブロック文です.

if-else-if構造の最後のelse部分は,他の状態を満たすことのないnone-of-the-above または デフォルトの場合をハンドルします.
時々,デフォルトとして明示的なアクションはありません.
そのような場合,引きずられたelse文が省略されたか,想定外の状態をキャッチするエラーチェック用に使われます.

LRM読解(Chap.6 代入~Assignments)

2008/09/23Verilog::文法import

6. 代入~Assignments

代入は,netや変数に値を設定するための基本的なメカニズムです.2つの基本的な代入の書式があります.

  • netへの値代入である,常時代入(continuous assignment)
  • 変数への値代入である,手続型代入(procedural assignment)

追加の書式が2つあります.LRM9.3で記す手続型常時代入(procedural continuous assignments)と呼ばれる, assign / deassign と force / release です.代入は,等号('=')またはノンブロッキング手続型代入('<=')で分けられた,左辺(LHS)と右辺(RHS)の2つの部分で構成されます.右辺は,評価された結果,値となるどのような式にでもできます.
左辺は,右辺の値を代入するための変数を示します.
左辺は,代入が常時代入か手続型代入かに基づいて,下表に示す書式のうち1つをとることができます.

Statement typeLeft-hand side (LHS)
Continuous assignmentネット(ヴェクタorスカラ) Net (vector or scalar)
ネットのヴェクタのビットセレクト(ビット固定の場合のみ) Constant bit select of a vector net
ネットのヴェクタの部分選択(選択位置固定のみ) Constant part select of a vector net
ネットのヴェクタの要素指定(index固定) Constant indexed part select of a vector net
上記の4つのLHSのいずれかの連結 Concatenation of any of the above four LHS
Procedural assignment変数(ヴェクタorスカラ) Variables (vector or scalar)
reg/integer/time型変数のビットセレクト(ビット固定の場合) Bit-select of a vector reg, integer, or time variable
reg/integer/time型変数のヴェクタの部分選択(選択位置固定) Constant part select of a vector reg, integer, or time variable
メモリワード Memory word
reg/integer/time型変数のヴェクタの要素指定(index固定) Indexed part select of a vector reg, integer, or time variable
bit選択reg/部分選択reg/regの連結 Concatenation of regs; bit or part selects of regs

6.1 常時代入 ~ Continuous assignments

常時代入は,ヴェクタとスカラ両方のネット上を駆動します.この代入は,右辺の値が変化したときに生じます.
常時代入は,ゲートの内部接続を与えることなく,組み合わせロジックをモデル化する方法を提供します.代わりに、モデルはネットを駆動する論理式を指定します.

Syntax:

net_declaration ::= (From Annex A - A.2.1.3)
  net_type [ signed ] [ delay3 ] list_of_net_identifiers ;
  | net_type [ drive_strength ] [ signed ] [ delay3 ] list_of_net_decl_assignments ;
  | net_type [ vectored | scalared ] [ signed ] range [ delay3 ] list_of_net_identifiers ;
  | net_type [ drive_strength ] [ vectored | scalared ] [ signed ] range [ delay3 ] list_of_net_decl_assignments ;
  | trireg [ charge_strength ] [ signed ] [ delay3 ] list_of_net_identifiers ;
  | trireg [ drive_strength ] [ signed ] [ delay3 ] list_of_net_decl_assignments ;
  | trireg [ charge_strength ] [ vectored | scalared ] [ signed ] range [ delay3 ] list_of_net_identifiers ;
  | trireg [ drive_strength ] [ vectored | scalared ] [ signed ] range [ delay3 ] list_of_net_decl_assignments ;

list_of_net_decl_assignments ::= (From Annex A - A.2.3)
  net_decl_assignment { , net_decl_assignment }

net_decl_assignment ::= (From Annex A - A.2.4)
  net_identifier = expression

continuous_assign ::= (From Annex A - A.6.1)
  assign [ drive_strength ] [ delay3 ] list_of_net_assignments ;

list_of_net_assignments ::=
  net_assignment { , net_assignment }

net_assignment ::=
  net_lvalue = expression

6.1.1 ネット宣言代入 The net declaration assignment

最初から二つのネット宣言の選択肢は LRM3.2で議論しました.
ネット宣言代入の三つ目の選択肢は,ネット宣言と同じ文中での常時代入を許可します.

例:下記は,常時代入のネット宣言記述の例です.

  wire (strong1, pull0) mynet = enable ;

注意:
ネットは一度だけ宣言できるので,唯一のネット宣言代入は,特定のネットで作られます.これは常時代入文と酷く違います.1つのネットは,常時代入記述の複数代入を可能とします.


6.1.2 The continuous assignment statement

常時代入文は,ネットデータ型の常時代入を置くものとします.
ネットは,明示的に宣言されるか,LRM 3.5で定義した暗黙的な宣言ルールにしたがって,暗黙的な宣言を継承するでしょう.
ネットにおける代入は,常時でかつ自動的です.これは,右辺式のオペランドの値が変わることを意味します.右辺全体が評価されて,もし新しい値が前の値と異なるならば,新しい値が左辺に代入されます.


6.1.3 遅延 ~ Delays

常時代入に与えられる遅延は,右辺のオペランド値の変化と,左辺への代入との間の時間間隔を指します.
左辺がスカラなネットであれば,ゲート遅延と同様に扱われるものとします.出力の立ち上がり・立下り・ハイインピへの変化時間を異なる遅延で与えることができます.(LRM 7参照)
もし左辺がヴェクタのネット型であれば,最大3つの遅延が適用できます.
以下のルールにより,どの遅延が代入を制御するのかを決定します.

  • 右辺が非ゼロからゼロへ遷移するならば,立下り遅延が使われます.
  • 右辺が'z'へ遷移するならば,ターンオフ遅延が使われます.
  • そのほかの場合,立ち上がり遅延が使われます.

ネット宣言部で,常時代入中に遅延を与えることは,ネット遅延を与えることとは異なるように扱われ,ネットへの常時代入が作られます.

以下の例のように,ネット宣言部での,遅延時間がネットへ適用されることができる.

wire #10 wireA;

このネット遅延と呼ばれる記述は,他の文からwireAに適用される値の変化が,10時間単位だけ遅延することを意味します.

宣言時に常時代入があるとき,その遅延は常時代入の一部であり,ネット遅延ではありません.
したがって,ネット上の他のドライバの遅延を加算しません.
なお,その代入がヴェクタネット型であれば,立ち上がりと立下り遅延は,宣言時に代入が含まれているならば,個々のビットには適用されません.
前の変化が左辺に伝播する時間がある前に,右辺のオペランドが変化するような場合,以下のステップがとられます.

  1. 右辺式の値が評価されます
  2. 右辺の値が,左辺への伝播が予定されていた値と異なる場合,現時刻のスケジューリングからはずします.
  3. 新しい右辺の値が,左辺の値と同じ場合,イベントはスケジューリングされません.
  4. 新しい右辺の値が,現在の左辺の値と異なる場合,遅延は,左辺の現在の値と右辺の新しく計算された値と命令文で示された値を用いて,通常の方法で計算されます.新しい伝播イベントは,未来の遅延時間単位で起きるようにスケジューリングされます.

6.1.4 強度 ~ Strength

常時代入の駆動強度(driving strength)は,ユーザにより指定されます.
以下の型のスカラネット方への代入でのみ適用されます.

wire  tri  trireg  wand  triand  tri0  wor  trior  tri1

常時代入の駆動強度は,キーワード'assign'を用いることで,ネット宣言中または単独の代入で指定できます.
強度仕様が与えられるならば,ネット型もしくはassign文の後のすぐ近くで遅延指定よりも前に無ければならない.

駆動強度仕様は,ネットに1が代入されるときに適用される1つの強さの値と,0が代入されるときに適用される2つ目の強さの値とからなる.以下のキーワードは,1の代入のための強さの値を示す.

supply1  strong1  pull1  weak1  highz1

以下のキーワードは,0の代入のための強さの値を示す.

supply0  strong0  pull0  weak0  highz0

2つの強さ指定の順序は,調停される.以下の2つのルールが駆動強度仕様の使い方を制限する.

  • 強さ定義((highz1, highz0) と (highz0, highz1))は,異常な構成(illegal constructs)として扱う.
  • 駆動強度指定がない場合は,(strong1, strong0)をデフォルトとして扱う.


6.2 手続型代入 ~ Procedural assignments

手続型代入の主な議論は LRM9.2で行う.しかし,本節では,基本思想の記述は,常時代入と手続型代入との間の違いを明らかにします.
LRM 6.1で述べらているように,常時代入は,ゲートがネットを駆動する方法と似たようなマナーでネットを駆動します.右辺式は,ネットを常時駆動するような組み合わせ回路のようなものが考えられるでしょう.
対照的に,手続型代入は変数に値を代入します.代入は期間を持ちません.変わりに,変数は,次の手続型代入まで,代入の値を保持します.

手続代入は,always文, initial文, task文, function文のような手続き中にあり,トリガ代入と考えられます.

シミュレーション中,実行の流れが手順の中で代入に達すると,トリガは現れます.条件文は,代入に達するのを制御できます.
イベント制御,遅延制御,if文,case文,ループ文は,全て代入文が評価されるかどうかの制御に使えます.LRM 9で詳細を与え,例示します.


6.2.1 変数宣言代入 ~ Variable declaration assignment

変数宣言代入は,値を変数に代入するような,手続型代入の特殊なケースです.変数宣言と同じ命令文中に,変数に初期値をおくことができます.

  • 代入は,定数式とします.
  • 代入に期間はありませんが,代わりに変数は次の代入まで値を保持します.
  • アレイ型への変数宣言代入は許可されません.
  • 変数宣言代入は,モジュールレベルにおいてのみ許されます.

例文

Example 1 Declare a 4 bit reg and assign it the value 4.
  reg[3:0] a = 4'h4;
  This is equivalent to writing:
  reg[3:0] a;
  initial a = 4'h4;

Example 2 The following example is not legal.
  reg [3:0] array [3:0] = 0;

Example 3 Declare two integers, the first is assigned the value of 0.
  integer i = 0, j;

Example 4 Declare two real variables, assigned to the values 2.5 and 300,000.
  real r1 = 2.5, n300k = 3E6;

Example 5 Declare a time variable and realtime variable with initial values.
  time t1 = 25;
  realtime rt1 = 2.5;

注意:
同じ変数が,initialブロックと変数宣言代入の両方で異なる値を代入されるとき,評価順序は未定義です.
# initial blockのしょっぱなと,変数宣言のしょっぱなは,時間的には同じで,かつシミュレーション時間のゼロからだけど,仕様上は優先順位を設けない,ということですね.(はまったきがするなぁ)
# initial blockの先頭で '#1'とかしておくと良いかも,かも,かも... (その前にmodule resetかけたほうがよいよぃょぃ...


6.2.2 Variable declaration syntax

syntax

integer_declaration ::= (From Annex A - A.2.1.3)
  integer list_of_variable_identifiers ;

real_declaration ::=
  real list_of_real_identifiers ;

realtime_declaration ::=
  realtime list_of_real_identifiers ;

reg_declaration ::=
  reg [ signed ] [ range ] list_of_variable_identifiers ;

time_declaration ::=
  time list_of_variable_identifiers ;

real_type ::= (From Annex A - A.2.2.1)
  real_identifier [ = constant_expression ]
  | real_identifier dimension { dimension }

variable_type ::=
  variable_identifier [ = constant_expression ]
  | variable_identifier dimension { dimension }

list_of_real_identifiers ::= (From Annex A - A.2.3)
  real_type { , real_type }

list_of_variable_identifiers ::=
  variable_type { , variable_type }