LRM読解(Chap.10-3)

2008/11/05Verilog::文法import

10.3 Functions と function呼び出し ~ Functions and function calling functionの目的は,式中で使用するための値を返すことです.この節では,functionの定義の仕方と使い方について解説します.


10.3.1 Function宣言

syntax

function_declaration ::= (From Annex A - A.2.6)
    function [ automatic ] [ signed ] [ range_or_type ]
      function_identifier ;
      function_item_declaration { function_item_declaration }
      function_statement
    endfunction
  |
    function [ automatic ] [ signed ] [ range_or_type ]
      function_identifier ( function_port_list ) ;
      block_item_declaration { block_item_declaration }
      function_statement
    endfunction

function_item_declaration ::=
    block_item_declaration
  | tf_input_declaration ;

function_port_list ::=
  { attribute_instance } tf_input_declaration
  { , { attribute_instance }tf_input_declaration }

tf_input_declaration ::=
    input [ reg ] [ signed ] [ range ] list_of_port_identifiers
  | input [ task_port_type ] list_of_port_identifiers

range_or_type ::=
  range | integer | real | realtime | time

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

block_reg_declaration ::=
  reg [ signed ] [ range ]
  list_of_block_variable_identifiers ;

list_of_block_variable_identifiers ::=
  block_variable_type { , block_variable_type }

block_variable_type ::=
    variable_identifier
  | variable_identifier dimension { dimension }

function定義は,'function'キーワードで始まり,オプショナルで'automatic'が続き,符号('signed')指定,rangeや関数の戻り値の型,function名と続いてから,セミコロン,または親で閉じたfunction port listにセミコロンとなり,'endfunction'で終わります.

'range_or_type shall'の使用はオプションです.'range'や'type'なしで定義されたfunctionは,戻り値はデフォルトで1bit reg型になります.もし使われたならば,'range_or_type'は,real型,integer型,time型,realtime型,[n:m] bit幅指定の値となるfunctionの戻り値を与えます.


A function shall have at least one input declared. functionは,たった一つの入力宣言を持ちます.keyworf 'automatic'は,各再帰呼び出しのために動的に確保される再帰可能なfunctionを宣言します.

  • automatic functionのitemは,階層参照('hierarchical references')によるアクセスができません.
  • automatic functionは,階層名('hierarchical name')を使うことで,起動することができます.

function入力は,2つの方法のうちの1つで宣言されます.

1つ目の方法は,セミコロンに続いてfunction名を持ちます.セミコロンのあと,1つ以上のオプション的な入力は,後述するblock item宣言と混ざって宣言します.function item宣言のあと,ビヘイビア文とendfunction keywordがあります.

2つ目の方法は,function名のあと,開き丸括弧と1つ以上の入力宣言をコンマ区切りで持ちます.全ての入力宣言のあと,閉じ丸括弧とセミコロンがあります.セミコロンのあと,0以上のblock itemが宣言され,続けてビヘイビア文,endfunction keywordとなります.


例:
以下の例は,'range'定義を使った,getbyteという名のfunctinoを定義します.

function [7:0] getbyte;
  input [15:0] address;
  begin
  // code to extract low-order byte from addressed word
  . . .
  getbyte = result_expression;
  end
endfunction

function宣言の2つ目の様式を使って,以下のように定義することができます.

function [7:0] getbyte (input [15:0] address);
  begin
    // code to extract low-order byte from addressed word
    . . .
    getbyte = result_expression;
  end
endfunction


10.3.2 関数からの戻り値 ~ Returning a value from a function

function定義は,暗黙的にfunctionと同じ名前で,関数内部の宣言をするものとします.この変数は,デフォルトで1bit reg変数か,function宣言中のtypeで与えられる型と同様になります.function定義は,function戻り値をfunction名と同じ名前の内部変数への代入によって,関数からの戻り値を初期化します.

function宣言と同じscopeにおいて,function名と同じ名前のobjectを宣言することはイリーガルです.関数内において,function内の式で使われる,function名の暗黙的な変数があります.これはまた,function内のscopeにおいても,function名と同じ名前のobjectを宣言することはイリーガルです.

以下のLRM 10.3.1の例の行は,このコンセプトを示します.

getbyte = result_expression;


10.3.3 function呼び出し ~ Calling a function

function呼び出しは,式中のオペランドです.function呼び出しは,以下の様式です.

function_call ::= (From Annex A - A.8.2)
  hierarchical_function_identifier{ attribute_instance } ( expression { , expression } )

function呼び出しへの,引数の評価順序は,未定義です.

例)
以下の例は,LRM 10.3.1で定義されたgetbyte functionを2回呼び出した結果を結合して,wordを作ります.

  word = control ? {getbyte(msbyte), getbyte(lsbyte)}:0;


10.3.4 functionルール ~ Function rules

functionはtaskよりも多くの制約があります.以下の6つのルールが,使用法を抑制します.a) function定義は,時間制御文(time-controlled statements,'#','@',"wait")を含んではならない.b) functionはtaskをenableにしてはならない.c) function定義は,少なくとも1つの入力引数を含みます.d) function定義は,output/inoutと宣言された引数を持ちません.e) function定義は,function名と同じ名称の内部変数への代入による戻り値の代入を含みます.f) functionは,ノンブロッキング代入を持ちません.A function shall not have any non blocking assignments.


例)
この例は,integer値を返す"factorial"と呼ばれるfunctionを定義します.この"factorial" functionは,反復して呼び出され,戻り値を表示します.

module tryfact;
  // define the function
  function automatic integer factorial;
    input [31:0] operand;
    integer i;
    if (operand >= 2)
      factorial = factorial (operand - 1) * operand;
    else
      factorial = 1;
  endfunction

  // test the function
  integer result;
  integer n;

  initial begin
    for (n = 0; n <= 7; n = n+1) begin
      result = factorial(n);
      $display("%0d factorial=%0d", n, result);
    end
  end
endmodule // tryfact

The simulation results are as follows:

0 factorial=1
1 factorial=1
2 factorial=2
3 factorial=6
4 factorial=24
5 factorial=120
6 factorial=720
7 factorial=5040


10.3.5 constant functionの使い方 ~ Use of constant functions

"Constant function calls"は,"elaboration"時(LRM 12.1.3)において,複雑な値の計算の構築のサポート使われます."Constant function call"は,functionへの引数が定数式("constant expressions")である,呼び出しモジュールへのローカルな"constant function"のfunction起動です."Constant function call"は,以下の制約を満足する,通常のVerilog functionsのサブセットです.

  • 階層的な参照を含まない
  • constant functionの中で呼び出されたどんなfunctionも,current moduleへの局所的なconstant functionになります.(Any function invoked within a constant function shall be a constant function local to the current module.)
  • System functions は呼び出されないこと.
  • "constant function"の中のすべての"system tasks"が無視されるものとします。
  • "constant function"の中の"system function"は,イリーガルになります.(All system functions within a constant function shall be illegal.)
  • 呼び出す"system task"は"$display"で,"elaboration time"において呼び出されたときは無視されます.(The only system task that may be invoked is $display, and it shall be ignored when invoked at elaboration time.)
  • 関数内で使われている全てのparameter値は,"constant function"呼び出しを使う前に定義されるべき.
    i.e. "constant function"呼び出しの評価で使われるどんな"parameter"も,
    元の"constant function"呼び出し位置で,その"parameter"の使用を構成する.(適用する?)
    
  • "parameter"でもなく,"function"でもない全ての識別子は,current functionへ局所的として宣言されるべき.それら(they:functions?)が,defparam文(LRM 12.2.1)によって,直接的・間接的に影響を受ける"parameter"を使うならば,結果は未定義です.これは,errorを提供できるか,または,"constant function"が不定値を返すことができます.
  • "generate"scope内で宣言されない
  • 定数式を要求するあらゆるコンテキスト内で,"constant function"自身を使わない.(They shall not themselves use constant functions in any context requiring a constant expression.)

"constant function call"は,"elaboration"("綿密な仕上げ"の意)の時に評価されます."elaboration"実行は,simulation時やelaboration時の複数の関数呼び出し間で使われる,変数の初期値に影響を与えない.これらの場合において,その変数は,通常のsimulationのために初期化されます.

例)
This example defines a function called clogb2 that returns an integer which has the value of the ceiling of the log base 2.

module ram_model (address, write, chip_select, data);
  parameter data_width = 8;
  parameter ram_depth = 256;
  localparam adder_width = clogb2(ram_depth);   //(訳コメント)定数項に対してfunctionを使う,てことですね.. やっと意味がわかった..

  input [adder_width - 1:0] address;
  input write, chip_select;
  inout [data_width - 1:0] data;

  //define the clogb2 function
  function integer clogb2;
    input depth;
    integer i,result;
    begin
      for (i = 0; 2 ** i < depth; i = i + 1)
        result = i + 1;
      clogb2 = result;
    end
  endfunction
reg [data_width - 1:0] data_store[0:ram_depth - 1];
//the rest to the ram model

An instance of this ram_model with parameters assigned:

ram_model #(32,421) ram_a0(a_addr,a_wr,a_cs,a_data);

LRM読解(Chap.10-2)

2008/11/05Verilog::文法import

10.2 Tasks and task enabling

taskは,taskに渡される変数の引数を定義して,結果を受ける変数定義の構文からenableにされます.

制御は,taskが完了した後で,processを有効に戻します.したがって,taskがタイミング制御を有した場合,taskをenableにした時刻と,制御が戻った時刻に差異が生じえます.taskは他のtaskをenableにすることができ,さらにそのtaskが別のtaskをenableにする数に上限は無いです.

どれだけのtaskがenableになろうとも,制御はすべてのenableにされたtaskが完了するまで返ってきません.



10.2.1 Task declarations

task_declaration ::= (From Annex A - A.2.7)
    task [ automatic ] task_identifier ;
      { task_item_declaration }
      statement
    endtask
  | task [ automatic ] task_identifier ( task_port_list ) ;
      { block_item_declaration }
      statement
    endtask

task_item_declaration ::=
  block_item_declaration
  | { attribute_instance } tf_ input_declaration ;
  | { attribute_instance } tf_output_declaration ;
  | { attribute_instance } tf_inout_declaration ;

task_port_list ::=
  task_port_item { , task_port_item }

task_port_item ::=
    { attribute_instance } tf_input_declaration
  | { attribute_instance } tf_output_declaration
  | { attribute_instance } tf_inout_declaration

tf_input_declaration ::=
    input [ reg ] [ signed ] [ range ] list_of_port_identifiers
  | input [ task_port_type ] list_of_port_identifiers

tf_output_declaration ::=
    output [ reg ] [ signed ] [ range ] list_of_port_identifiers
  | output [ task_port_type ] list_of_port_identifiers

tf_inout_declaration ::=
    inout [ reg ] [ signed ] [ range ] list_of_port_identifiers
  | inout [ task_port_type ] list_of_port_identifiers

task_port_type ::=
  time | real | realtime | integer

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

block_reg_declaration ::=
  reg [ signed ] [ range ]
  list_of_block_variable_identifiers ;

list_of_block_variable_identifiers ::=
  block_variable_type { , block_variable_type }

block_variable_type ::=
    variable_identifier
  | variable_identifier dimension { dimension }

There are two alternate task declaration syntaxes. 2種類のtask宣言書式があります.

1つ目の書式は,"task"キーワードから始まり,オプション"automatic"やタスク名とセミコロンが続きます.そして,"endtask"で終わります."automatic"キーワードは,"automatic task"を宣言します.それは,ダイナミックにそれぞれの同時発生のタスクエントリーに割り当てられた,すべてのタスク宣言について再代入可能です.

"task item"宣言は,以下のように定義できます.

  • Input 型引数
  • Output 型引数
  • Inout 型引数
  • 手続きブロックで宣言可能な全ての型

2つめの書式は,"task",続いて"task名",丸括弧で閉じた"task_port_list"で始まります."task_port_list"は,0以上のコンマ区切りの"task_port_items"です.丸括弧を閉じたあとにセミコロンがあります."task body"が続き,そして"endtask"がきます.

どちらの書式においても,ポート宣言は,"tf_input_declaration","tf_output_declaration","tf_inout_declaration"で定義されるように同じ書式です.


オプション"automatic"キーワードのないタスクは,"static task"で,全ての宣言されたアイテムは静的に確保されます.これらのitemは,同時実行する全てのtaskの使い方間で共有されます.

オプションキーワード"automatic"のあるtaskは,"automatic tasks"です."automatic task"内の全てのアイテムは,それぞれの呼び出しに対して動的に確保されます."automatic task"のアイテムは,階層的な参照によりアクセスされます."automatic task"は,それらの階層的な名前を使うことで,起動されます.



10.2.2 Task enabling and argument passing

taskを有効にする書式は,丸カッコ内のコンマ区切りの式リストのような引数を渡すことです.正式な書式を以下に示す.

task_enable ::= (From Annex A - A.6.9)
  hierarchical_task_identifier [ ( expression { , expression } ) ] ;

task enableing書式のための引数リストは,オプショナルです.もし,引数リストが与えられるならば,そのリストは式のリスト順が,タスク定義内の引数リストの並び順と一致する必要があります.

タスクの引数がinputとして宣言された場合,関連する式はどのような式にもなれます.引数内の式評価順序は未定義です.タスクの引数がoutputまたはinoutとして宣言された場合は,厳密に手続き型代入(LRM9.2)の左辺として正しい式です.以下のitemsは,この要求を満たします.

  • reg型,integer型,real型,realtime型,time型
  • Memory references
    Concatenations of reg, integer, real, realtime and time variables
  • Concatenations of memory references
    Bit-selects and part-selects of reg, integer, and time variables

task enabling構文の実行は,enabling構文でリストされた式から,task内で定義された引数へ,入力値が渡されます.

taskからの返り処理は,task output型とinput型の引数から,task enabling構文内の相当する変数へ,値が渡されます.

All arguments to the task shall be passed by value rather than by reference (that is, a pointer to the value). taskへの全ての引数は,参照(値へのポインタ)よりも値渡しのほうがよい.

例1) 以下の例は,5つの引数を持つタスク宣言の基本構造を表します.

task my_task;
input a, b;
inout c;
output d, e;
  begin
    . . . // statements that perform the work of the task
    . . .
    c = foo1; // the assignments that initialize result regs
    d = foo2;
    e = foo3;
  end
endtask

2つ目のタスク宣言様式を使うと,以下のように定義できます.

task my_task (input a, b, inout c, output d, e);
  begin
    . . . // statements that perform the work of the task
    . . .
    c = foo1; // the assignments that initialize result regs
    d = foo2;
    e = foo3;
  end
endtask

以下の分はtaskをenableにします.

my_task (v, w, x, y, z);

task enabling引数 (v,w,x,y,z) は,タスク宣言時の(a,b,c,d,e)に相当します.task enablingの時刻において,inoput,inout型の引数(a,b,c)は,(v,w,x)で渡された値を受け取ります.例えば,task enablingの実行は,有効に以下の代入の原因を呼びます.

a = v;
b = w;
c = x;

task処理の一部のように,my_taskのためのtask定義は,c,d,eへ計算結果をおきます.task完了時,計算値をprocessを呼び出した元へ返すための以下の代入が適用されます.

x = c;
y = d;
z = e;

例2) 以下の例は,"traffic light sequencer"の記述をtsakを使って表します.

module traffic_lights;
  reg clock, red, amber, green;
  parameter on = 1, off = 0, red_tics = 350,
  amber_tics = 30, green_tics = 200;

  // initialize colors.
  initial red = off;
  initial amber = off;
  initial green = off;

  always begin // ライト制御用のシーケンス
    red = on; // 赤色on
    light(red, red_tics); // wait
    green = on; // 緑色on
    light(green, green_tics); // wait.
    amber = on; // 琥珀色on
    light(amber, amber_tics); // wait.
  end

  // task : 立ち上がりエッヂを'tics'回待って,'color'ライトをオフにする.
  task light;
  output color;
  input [31:0] tics;
    begin
      repeat (tics) @ (posedge clock);
      color = off; // ライトオフ
    end
  endtask

  always begin // クロック波形
    #100 clock = 0;
    #100 clock = 1;
  end
endmodule // traffic_lights.


10.2.3 Task memory usage and concurrent activation

タスクは,同時に1つ以上enableにされるかもしれません.automaticタスクの全ての変数は,その実施に特定の状態を保存するために,それぞれの同時発生のタスク実施で複製されるものとします.

staticタスクの全ての変数は,タスクの同時発生の起動の数にかかわらず,静的になるでしょう.なぜならば,モジュールインスタンスそれぞれで宣言している局所変数に対応するただ一つの変数があるので.しかし,モジュールインスタンスの異なるstaticタスクは,互いからの別々の格納場所があるものとします.


staticタスクで宣言された変数は,呼び出し間でそれらの値を保有するものとします.staticタスクで宣言された変数は,LRM 3.2.2で記述するように,デフォルト初期値に初期化されます.automaticタスクで宣言された変数は,変数のスコープに入ったときに,デフォルト初期値に初期化される.なぜならば,automaticタスクで宣言された変数は,task起動の終了時に,de-allocateされるので,変数はその後の場所では参照される所望の構造で使われない.*1

automatic taskのlocal variableに対してやってはいけないことを以下に示す.

  • ノンブロッキング代入文や手続き型連続代入文を使って,値の代入をしないこと.
  • 手続き型代入文や手続き型force文で参照されないこと.
  • ノンブロッキング代入文のintra代入イベント制御で参照されないこと.
  • $monitorや$dumpvarsのようなシステムタスクでトレースされないこと.

*1 : 訳がテキトウだ.auto変数は scopeを外れると揮発する,ということで把握しておくとよいだろう,

LRM読解(Chap.10-1)

2008/11/05Verilog::文法import

TITLE: 10. Tasks and functions taskとfunctionは,記述中のあらゆる場所からの共通の手続きを実行するアビリティを提供する.ソースコードの可読性・デバッグ性を容易にするために,大きな手続きを小さな手続きに分解することも提供する(意訳).この節は,taskとfunctionの間の差異について議論し,taskとfunctionの定義の仕方と起動の仕方について記述し,それぞれの例を提供します.

10.1 taskとfunctionとの差異 ~ Distinctions between tasks and functions

以下の規則は,funtionとtaskとを区別します.

  • functionは,1シミュレーション時間ごとに実行される.taskは,時間制御文を含むことができる.
  • functionはtaskを有効にできない.taskは他のtaskおよびfunctionを有効にできる.
  • functionは,最低1つのinput型の引数を持ち,output型やinout型の引数を持たない.taskは0以上の任意の型の引数を持つことができる.
  • functionは1つの値を返す.taskは値を返せない.

functionの目的は,1つの値を返すことによって,入力の値に対する応答をすることです.taskは複数のゴールをサポートすることができ,複数の返り値を計算することができます.しかし,outputまたはinput型の引数のみが,taskの呼び出しから返り値を渡すことができます.*1 functionは,式のオペランドのように使われます.オペランドの値は,関数による返り値です.

Example
taskまたはfunctionは,16bit wordを交換することとして定義することができます.taskは交換後のwordをoutput引数で返します.switch_bytesと呼ぶtaskを有効にするためのソースコードは,下記の例のように見えます.

switch_bytes (old_word, new_word);

task:switch_bytesは,old_wordにbytesをとり,byte orderを入れ替えて,new_wordにおきます.word-switching functionは,functionの返り値として入れ替え後の値を返します.なので,function:switch_bytesの関数呼び出しは,下記の例のように見えます.

new_word = switch_bytes (old_word);

*1 : 訳注:関数のように返り値を持たない.例を参照のこと.

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の立下りエッヂとが,同じシミュレーション時間に生じても,それぞれ分けて検出されます.