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 }