第4回補足資料・スクリプトの実際

再現してみたスクリプトです。

これは一部で、ネットリストの端子定義部から、接続検証に必要なデータ(人手作成)の検証に必要な、端子名、入出力属性などを抜き出して、検証に使いやすいように配列に納める、ということをしています。

実際は、この部分の後ろにデータの検証をする部分が来るのですが、それは割愛します。

扱うネットリストは、論理検証が終わったもの、という前提なので、端子の過不足がないこと、文法的におかしなことは無いこと、というのが大前提で当時もスクリプトを書きました。

若干端子の過不足を調べてNGの場合に処理を中断する、などのエラーチェックは入れてはいますけど。

おそらく専門家が見たら顔をしかめそうな見通しの悪いコードになっているのではないかと思います。お許し下さい

なお、古い実装のawkではおそらく動きません。当方ではGNU awkで動作チェックしましたが、nawkでも動くかも知れません。


#! /usr/local/bin/gawk -f
BEGIN {
    
#端子名の抽出
    # このBEGINセクションでは、ネットリストの中から、対象となるブロックの定義を探し出して、
    # インタフェース定義で定義されている端子名を拾い出し、その後に出てくる端子の入出力属性定義との
    # 端子名の一致を取り、定義されている端子と端子の入出力属性を配列に取り込む。
    #
    # 定義されている配列は以下の通り
    # termname[]  : インタフェース定義から拾い上げた端子名が入った配列。
    # direction[] : 端子の入出力属性が入った連想配列。端子名を添え字にして参照する。
    #
    # 起動時にコマンドラインから
    #  -v NETLISTFILE=ネットリストのファイル名 -v BLOCKNAME=対象ブロックのブロック名 検証したい端子情報ファイル
    #  を指定して起動する想定のスクリプト
    #  たとえば、
    #  gawk -f scriptfile -v NETLISTFILE=netlist.txt -v BLOCKNAME=TESTMODULE inputfilename.txt
    #  などとする。 -vオプションで変数定義をしないとBEGINセクションで使えないことに注意
    #
    #NETLISTFILE = "testdata.txt";
    #BLOCKNAME  = "TESTMODULE";
    
    print NETLISTFILE " " BLOCKNAME;  #デバッグ用出力
    
    while( (getline ibuf < NETLISTFILE) > 0 ) { #ネットリストを読んで文字列BLOCKをさがす
 
      if(!((index( ibuf, "BLOCK" ) > 0) && (index( ibuf, BLOCKNAME ) > 0))) {
        ibuf ="";
        continue;
      }
 
      linebuf = ibuf;                            #見つかったら、その行をバッファに置く
      while( index( ibuf, "@" != 0 )  ){         #継続記号@があるかどうかテスト
        if( getline ibuf < NETLISTFILE != 1 )  #継続記号があったときは、更に1行読む
          exit;                              #ここでファイルが読み込めないときは異常終了
        linebuf = linebuf ibuf;                #追加で読んだ行をバッファの後ろに追加
      }

      position = index( linebuf, "BLOCK" );

 #文字列BLOCKの次の文字からバッファの最後までをバッファにコピー
      termbuf = substr( linebuf, position + 5, length( linebuf ) - (position + 5) + 1 );

      gsub( "[ @]", "", termbuf );               #スペースと@を全て削除

      split( termbuf, termname, "," );
      for( item in termname ) {
        tmp = termname[item];
        direction[tmp] = "NON";                #信号属性格納配列の初期化。とりあえずNONで埋める
        print item " " tmp " " direction[tmp];
      }


 #入出力属性の抽出
      while( (getline ibuf < NETLISTFILE ) > 0 ) {

        if( match( ibuf, "^ *$" ) > 0 )
          continue;

        if( match( ibuf, "^ *END *$" ) > 0 )
          break;

        gsub( " +", " ", ibuf );               #複数のスペースを1個のスペースに置換
        gsub( " *, *", ",", ibuf );            #不要なスペースを除去
        split( ibuf, ibufarry );               #入力行を入力属性名とピン名列挙部に分ける

     #入力属性名を拾って配列に格納
        if(( ibufarry[1] == "INPUT"  ) || ( ibufarry[1] == "OUTPUT" ) || ( ibufarry[1] == "INOUT"  )) {
  
          split( ibufarry[2], pinlist, "," );   #ピン名列挙部を個々のピン名に分割

          for( item in pinlist ) {
            tmp = pinlist[item];
            if( ispinarry( tmp, termname ) == 0 ) {
              printf "illegal pin name : %s¥n", tmp;
              exit;
            }
            direction[tmp] = ibufarry[1];   #信号属性格納配列に読み込んだ属性を格納
          }
        } else
          break;         #端子属性文がなくなったらあとは読む必要が無いのでbreak;
        }
      break; #目的とするBLOCK文が見つかったら、あとのBLOCK定義は読む必要がないのでbreak
    }
    
    for( item in termname ) {
     tmp = termname[item];
     print item " : " tmp " : " direction[tmp];
    }
    
}
#
# 指定した端子名がインタフェース定義部から抽出した端子名の中にあるかどうかをテストする関数
# 引数:
#  pin
#    含まれているかどうかをテストする端子の端子名
#  arry
#    インタフェース定義部で定義した端子名の配列
#  戻り値
#    1 端子名が配列に含まれている
#    0 端子名が配列に含まれていない
#    1より大きい数:含まれているが、重複している
#
function ispinarry( pin, arry ) {
    cnt = 0;
    for( ispinarryitem in arry ) {
 ispinarrytmp = arry[ispinarryitem];
 if( pin == ispinarrytmp ) {
#     print "match " pin "vs." ispinarrytmp; #デバッグ用出力
     cnt++;
 }
    }
#   print "pin match counter : " cnt;            #デバッグ用出力
    return cnt;
}

#ここからが、検証を実施するスクリプトの本体となる。このスクリプトでは、入力をそのまま出力する記述にしてある。

{
    print;
}