なぜ制御端子が必要か
制御端子は,手続きによって構造上の階層を扱うために導入された SFL言語のもっとも重要な概念です.これによって,静的な接続表現を使わずに複雑なシステムを記述できるようになりました.
静的な接続表現,すなわち回路図を使うべきでないという考えは多くの設計経験から得られたものです.
人は回路図からいったん動作を抽出しなければ回路を理解できません.回路図による設計では,設計の内容を接続に変換して記述し,逆に接続から動作を抽出理解して,設計を追加あるいは完成させていくという負担の大きい作業が必要です.
ところが,対象を構成要素間の接続で表すと,その構成要素はまたさらに下位の構成要素間の接続で表されるというように,接続記述は再帰的な (recursive) な性質をもっています.このため自然に階層化や部品化が行え,また工程によらず使用することができます.これが上に指摘した問題があるにもかかわらず回路図による設計が広く行われている理由です.
したがって,記述性を高めるには,動作 (手続き) と構造上の階層を両立させることがぜひとも必要でした.このために考えられたものが制御端子です.
制御端子の記述例
手続き (制御) を階層の外から内へ通過させるために制御入力端子を使います.たとえば,
abc.xyz();
は ,「abc という構成要素に xyz をしなさい」という指示を行っていることを表します.abc からみると xyz から制御が入ってくるので,xyz は制御入力端子と呼ばれます.制御入力端子には動作が対応つけられていますので,外からの指示によってその動作が起動されます.指示xyz を実行するために複数のマシン・サイクルが必要であれば,制御端子 xyz からさらに,たとえば,
instruct xyz par {
generate stg.tsk();
...
}
などとして,ステージ stg へジョブを生成することになります.instruct ... は制御端子に動作を対応させる形式です.ジョブの生成を表す形式も,
generate 対象.指示( );
となっていて,この 対象.指示( )という形式は SFL言語のキーとなる形式です.
3.4節の例の中で出て来た制御端子の起動は
do();
あるいは
do().result
でしたが,制御端子やステージの起動は () が名前の後につくことによって,他のデータ系の操作と区別がつけられています.制御内部端子や制御出力端子は名前だけで一意に定まるので上のような記述となりますが,サブモジュールの制御入力端子の起動はサブモジュール名で修飾する必要があり,
サブモジュール名.制御入力端子名();
となります.実はステージの起動も同じ様な考え方で形式が決められています.本来ステージの起動は,
ステージ名.タスク名();
なのですが,起動にジョブの生成と転送があるため,
generate ステージ名.タスク名();
と,
relay ステージ名.タスク名();
に分けてあります.なお,
do().result
の形式は制御端子の起動と結果の参照を合体させたものです.
さらにこの形式をサブモジュール名で修飾して,
ALU.add(ox11,oxff).sum
のようにすることもできます.これは ALU の add という制御入力端子を起動して得られた ALU の sum というデータ出力端子の値の意味となります.()内は制御入力端子を起動する時に渡す実引数(値)です.これらの実引数が ALU の何というデータ入力端子に与えられるかは 3.9節で説明する instr_arg 構文で指定されます.もちろん実引数は制御端子の起動を単独で (結果の参照と合体させないで) 行うときにも指定できます.
制御端子には,外側からの制御を表す制御入力端子や,外側への制御を表す制御出力端子の他に,内部の制御を表す制御内部端子があります.
何度も使う下請け的処理であって,かつ 1マシン・サイクル内のものは制御内部端子によりくくり出すことができます.SFL記述の中に同じような記述がたくさん現れるときは,制御内部端子の利用を検討すべきでしょう.