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文が省略されたか,想定外の状態をキャッチするエラーチェック用に使われます.