【手続補正書】
【提出日】平成17年3月11日(2005.3.11)
【手続補正１】
【補正対象書類名】明細書
【補正対象項目名】発明の詳細な説明
【補正方法】変更
【補正の内容】
【発明の詳細な説明】
【０００１】
【発明が属する技術分野】
本発明は、プログラム言語を用いてデジタル回路を記述し、そのソースリストをハードウェア記述言語、ネットリスト、または回路図等の回路情報に変換するデジタル回路の設計方法、およびその設計方法で記述されたソースリストをハードウェア記述言語、ネットリスト、または回路図等の回路情報に変換するコンパイラー、およびその設計方法で記述されたソースリストをコンピュータ上で実行させて結果を表示するシミュレータに関するものである。
【０００２】
【従来の技術】
従来からデジタル回路を設計するのに、ｖｅｒｉｌｏｇ  ＨＤＬとかＶＨＤＬとかのハードウェア記述言語が用いられている。しかし回路規模がシステムレベルの大規模になってくると、ハードウェア記述言語では全体の見通しが悪いのでトップダウン設計手法と言われる仕様記述から回路を合成する手法が使いづらいとか、シミュレータのシミュレーション速度が遅いとかの欠点が明らかになってきた。
【０００３】
そこで、近年ではＣやＣ＋＋のプログラミング言語でハードウェアを記述する手法が採用され始めた。例えば業界ではＳｙｓｔｅｍＣという名称の設計手法が提案されている。これによればＣシミュレータでシミュレーションできるのでハードウェア記述言語でのシミュレーションが遅いという問題点は克服している。しかしこの手法は記述方法に制約が多くかつハードウェア記述言語とほとんど同様な記述の仕方なので仕様記述でデジタル回路設計をするというトップダウン設計は難しいという問題点があった。
【０００４】
他にもＣやＣ＋＋のプログラミング言語でハードウェアを記述する設計手法は考案されているが、ハードウェア記述言語は同期設計によりレジスターが同時に変化するのを基本としており、プログラミング言語は順次処理を基本としているため、同時変化の記述がかなり難しく、そのため設計的な大きな制約を与えているという問題点があった。
【０００５】
また、従来のプログラミング言語からハードウェア記述言語に変換するコンパイラーは、上記のように大きな設計制約を与えているという問題点を有していた。
【０００６】
また、従来のシミュレータは上記のような大きな設計制約を与えたソースリストしかシミュレーションできないという問題点を有していた。
【発明が解決しようとする課題】
解決しようとする問題点は、Ｃプログラミング言語でハードウェアを記述するときに、同時変化の記述がかなり難しいとか、順次処理で記述せねばならないため設計が制約されてしまうという点である。
【０００７】
【課題を解決するための手段】
本発明は、プログラミング言語でレジスターを記述するときに、レジスターを示す第１の変数と、レジスターの入力を示す第２の変数とに分けて記述し、モジュール部での処理の後に第２の変数から第１の変数に一括して代入する一括代入部を設けたことを最も主要な特徴とする。また、プログラミング言語の順次処理による制約を軽減するために、モジュール部で使用する組み合わせ回路を定義するアサイン部をモジュール部の前に実行するように記述しているという特徴がある。また、複数のクロック、ゲーティド・クロック、または非同期リセット／セット等は設計を容易にするために一括代入部に記述しているという特徴がある。
【０００８】
【発明の実施の形態】
本発明は、Ｃプログラミング言語でハードウェアを記述したときに、同時変化の記述がかなり難しいとか、順次処理で記述せねばならないため設計が制約されてしまうという問題点を解決して、容易に設計できる手法を実現した。また、その設計手法に基づくコンパイラーやシミュレータを提供するものである。
【０００９】
【実施例】
図１は、本発明のデジタル回路の設計方法の１実施例のＣプログラミング言語で、例として２倍オーバーサンプリングＦＩＲフィルターのハードウェアを記述・設計したプログラムリストである。左端の数値は説明のための何行目かを示す行番号であり、「//」はそこから行の終わりまでがコメントであることを示し、それ以外はANSI規格に基づいたＣプログラミング言語で記述している。ここで、１行目から２０行目は宣言部、２２行目から４７行目はモジュール部、４９行目から５６行目は一括代入部、６６行目から７９行目はループ部である。
【００１０】
図１において１行目はファイルやコンソール入出力のライブラリーをインクルードするためのインクルード命令であり、２行目は文字列のライブラリーをインクルードするためのインクルード命令であり、３行目から７行目はキャストを定義している。ここで３行目は「unsigned char」を「BIT」に、４行目は同じく「unsigned char」を「BIT3」に定義しているが、これはハードウェア記述言語に変換したときそれぞれ１ビットと３ビットの接続端子またはレジスターに割り当てるためであり、Ｃプログラミング言語では１ビットとか３ビット幅の変数を定義することができないので便宜上８ビット幅の「unsigned char」に割り当てるためである。６行目と７行目の関係も同様である。
【００１１】
８行目と９行目は１行目でインクルードされた「stdio.h」内で定義されているファイル構造体へのポインターの宣言文であり、それぞれ入力ファイル、出力ファイルへのポインターを定義し、１０行目と１１行目はそれぞれ入力ファイル、出力ファイルを指定するための文字列変数の宣言文であり、１２行目はシミュレーション開始からのクロックの数を数えるシミュレーション用のクロックカウンターの宣言文であり、１３行目はファイルからデータを読み込むための変数の宣言文であり、１４行目と１５行目はそれぞれファイルからの入力データとファイルへの出力するための変数の宣言文であり、１６行目は外部から入力されるＬリセット信号の宣言文であり、１７行目は接続端子として用いられる乗算器出力の宣言文であり、１８行目から２０行目は各レジスター変数の宣言文である。ここで各レジスターは「＜変数名＞」と「＜変数名＞_i」の２つの変数で定義され前者はレジスターの出力を示し、後者はレジスターのＤ入力を示しており、これらの２つの変数をペアで宣言することによってレジスターであることを明示している。
【００１２】
２２行目から４７行目まではＦＩＲフィルター動作の関数 fir() で、４９行目から５６行目まではハードウェア記述言語で「非ブロッキング代入」と言われるレジスターがクロック同期で同時変化することと等価な動作をさせるための関数 non_blocking_assignment() であり、５８行目から８２行目はＦＩＲフィルター動作をシミュレーションするためのメイン関数 main() である。
【００１３】
プログラムが実行されると最初にメイン関数 main() から開始され、５９行目で入力ファイル名を聞いてくるので入力し、次に６０行目で出力ファイル名を聞いてくるので入力する。次に６１行目で入力ファイルを開き、もし開けなかったら６２行目でエラー表示をして終了する。次に６３行目で出力ファイルを開き、もし開けなかったら６４行目でエラー表示をして終了する。次に６５行目でクロックカウンター clk_cnt を０にリセットし、次に６６行目で６７行目から７８行目までをループし、６６行目から７９行目までのループ部を生成している。６７行目は state_cnt が５の時に入力ファイルからデータを読み込むことを示し、６８行目で入力ファイルから１つのデータを data_in に読み込み、もしファイルの最後まで来ていたら６６行目で示すループを終了する。６９行目は６８行目の fscanf() 関数は int型変数にデータを読み込むので１６ビットの short型変数の data1 にキャスト変換して代入する。７１行目は clk_cnt が０の時（ループの最初で） rst_n を０にして各レジスターにリセット信号を与え、０でないときは７２行目で rst_n を１にして各レジスターのリセット信号を解除する。７３行目はＦＩＲフィルターの本体である fir() 関数を呼び出している。７４行目は state_cnt が６または１の時に入力ファイルからのデータにＦＩＲフィルタリングした結果を出力ファイルに出力するタイミングを示し、２倍オーバーサンプリングのため２回出力する。７５行目は出力ファイルへの出力タイミングで data2 を int型変数にキャスト変換して出力ファイルに出力する。７７行目は非ブロッキング代入用の関数 non_blocking_assignment() を実行する。７８はクロックカウンターのインクリメントである。８０行目と８１行目は入力ファイルからの読み込みが終了したときに、入力ファイルと出力ファイルを閉じてプログラムを終了している。
【００１４】
次にＦＩＲフィルターの本体である fir() 関数を説明する。２３行目はローカル変数の宣言文である。２４行目は rst_n が０になったときにレジスターを非同期リセットするもので、２５行目から２７行目で各レジスターの出力をリセットしている。まず、先に４５行目から４６行目を説明すると、リセット解除された後 state_cnt を１から６を順番に繰り返すための処理で、 state_cnt が６の時は次に state_cnt を１にするために state_cnt_i を１にしておき、それ以外の時は state_cnt をインクリメントするために state_cnt_i に state_cnt + 1 を代入しておく。次に４１行目から４４行目を説明すると、４１行目で state_cnt が５の時に４２行目から４３行目の処理をすることを示し、４２行目で入力ファイルからのデータ data1 を０番目（最初）のデータ用シフトレジスターの入力 s_reg_i[0] に代入し、４３行目で各シフトレジスターの入力に１つ前のシフトレジスター出力を代入してシフト動作をさせる。次に２９行目は state_cnt の値に応じて処理を変えることを意味し、３０行目から３４行目までは state_cnt の値に応じて各シフトレジスターの値に各係数を掛けている。ここで２つのシフトレジスターの和をとっているのは対称な係数のため乗算回数を減らすためにあらかじめ加算しておくものである。３５行目は２倍オーバーサンプリングの値を１個おきに素通しするものであり、リップルによってクリップするのを防ぐために１より少し小さい係数を掛けている。係数は整数だが後で９ビット右シフトしているので５１２で割った値が実際の係数である。３６行目は演算しないときに乗算器を止めておくもので特に重要な意味はない。次に３８行目はＦＩＲ演算の最初とデータ素通し時に乗算器 mult の出力に９ビット右シフト時に４捨５入するために２５６を加算してアキュムレータの入力 acc_i に代入しておき、３９行目はそれ以外の時にアキュムレータ acc と乗算器 mult の和をアキュムレータの入力 acc_i に代入して累積加算する。最後に４０行目でアキュムレータの値の下位９ビットを切り捨てて出力データ data2 に代入する。
【００１５】
次に非ブロッキング代入処理を行う一括代入部の関数 non_blocking_assignment() を説明する。５０行目はローカル変数の宣言文である。５１行目は rst_n が１の時は、リセット解除されているので５２行目から５４行目までので各レジスターのＤ入力をレジスター出力に代入することによって、記述順序に関係なく各レジスターの同時代入と同じ動作をさせることができる。また rst_n が１でないときは、リセット中なので各レジスターのＤ入力はレジスターの出力に代入されない。このように、５１行目の判断処理と fir() 内の２４行目の判断処理によって非同期リセットが実現できる。
【００１６】
図２は、本発明のデジタル回路の設計方法の１実施例である図１のＣプログラミング言語で記述された２倍オーバーサンプリングＦＩＲフィルターのハードウェアを、ハードウェア記述言語の一種であるｖｅｒｉｌｏｇ  ＨＤＬへの変換されたＨＤＬコードの例である。ここでは、実回路を記述した関数 fir() のみを変換した例であり、左端の数値は説明のための何行目かを示す行番号である。
【００１７】
図２において、１行目はモジュール fir() の始まりを示し、かっこ内はその上位関数である関数 main() とやりとりする変数名を抽出して入出力リストとして記述してある。２行目はクロック信号 clk の宣言文で、図１のＣプログラムにはない入力信号であるが、Ｃプログラムはループ部の１巡をクロック同期の１クロックとしているので、クロック信号を新たに作って宣言している。３行目は入力信号 rst_n の宣言文で、図１の１６行目から変換している。４行目は入力信号 data1 の宣言文で、図１の１４行目から変換している。５行目は出力信号 data2 の宣言文で、図１の１５行目から変換している。６行目は出力信号 state_cnt の宣言文で、図１の１８行目から変換している。８行目は接続端子 mult の宣言文で、図１の１７行目から変換している。ここでは「LONG27」から２７ビット幅であることを判断している。また接続端子であるのに「reg」で宣言されているのは、この信号は１７行目から２６行目までの「always@」文で代入されているので、ｖｅｒｉｌｏｇ  ＨＤＬの規約によって「reg」で宣言している。１０行目はレジスター state_cnt の宣言文で、図１の１８行目から state_cnt と state_cnt_i が存在することからレジスターであることを判断し、また「BIT3」で宣言されていることから３ビット幅であることを判断して変換している。前述の６行目は、このレジスターの出力を直接出力していることを示している。１１行目は１０個のレジスター s_reg の宣言文で、図１の１９行目から s_reg と s_reg_i が存在することからレジスターであることを判断し、また [10] から１０個の配列であることを判断して変換している。１２行目はレジスター acc の宣言文で、図１の２０行目から acc と acc_i が存在することからレジスターであることを判断し、また「LONG30」で宣言されていることから３０ビット幅であることを判断して変換している。１４行目は整数型変数 i の宣言文で、図１の２３行目から変換している。このように、本発明によるＣプログラミング言語によるデジタル回路の記述は容易にｖｅｒｉｌｏｇ  ＨＤＬに変換できる。
【００１８】
次に１７行目から２６行目は図１の２９行目から３７行目を変換している。２８行目から３４行目は図１の３８行目から３９行目を変換している。３６行目は図１の４０行目を変換している。３８行目から４４行目は図１の４１行目から４４行目を変換している。４６行目から５２行目は図１の４５行目から４６行目を変換している。また、これらのレジスターの rst_n による非同期リセットの記述は、図１の２４行目から２８行目を変換して、各レジスターに分配して記述している。５４行目はこのモジュールの終了を示している。また、レジスターの代入に「＜＝」という記号が用いられているが、これはｖｅｒｉｌｏｇ  ＨＤＬの規約に基づく非ブロッキング代入文で、記述順序に関係なくクロックに同期して同時に変化することを示している。
図１で示される本実施例において、各レジスターのＤ入力をレジスター出力に代入するのに、 non_blocking_assignment() という特別な関数を設けたが、モジュールを記述する関数（ここでは fir() ）の中の最後に記述してもよい。また、モジュールを記述する関数の最初に記述してもよく、その理由は、各レジスターのＤ入力に代入された次のループで最初にレジスター出力に代入されるので、結果的にモジュールを示す関数の実行後に代入されることになるからである。
また、本実施例では、Ｄ入力はレジスターを示す変数の後ろに文字列「_i」を付けて表現したが、付ける文字列は何でもよく、また後ろではなく前に付けてもよい。また、２つの変数を隠蔽するためにマクロ定義をすることもでき、例を上げるとプログラムの先頭やプログラムの実行前に組み込まれるヘッダーファイルの中で次のようにマクロ定義できる。ここで「##」はトークン連結演算子と呼ばれるもので、文字列「_post_」とマクロ呼び出しされたトークン「regname」が連結される。これによって、「_post_」のような文字列がレジスターを示す変数の前に付けられる。
#define REG(t, regname)        static t regname, _post_##regname
プログラム内では次のように記述する。
REG(DWORD, xxx);
すると、実際にプログラムが実行するときに次のように変換され、２つの変数が定義される。
DWORD xxx, _post_xxx;
同様にヘッダーファイル内で、次のようにノンブロッキング代入をマクロ定義することができる。
#define REGupdate(regname)    regname = _post_##regname
モジュール記述の最後に、次のように記述する。
REGupdate(xxx);
すると、実際にプログラムが実行するときに次のように変換され、レジスターのＤ入力を示す変数からレジスターを示す変数に代入される。
xxx = _post_xxx;
各レジスターに対して連続して、「REGupdate()」を記述しておけば non_blocking_assignment() 内で一括代入したのと同様の動作をすることができる。
【００１９】
図３は、本発明のデジタル回路の設計方法の第２の実施例のブロック図であって、１は宣言部、２はアサイン部、３はモジュール部、４は一括代入部、５はループ部である。ただし、宣言部を除く各部は、ループ部内の各部の呼び出しを、アサイン部１、モジュール部３、一括代入部４の順で行えば、記述順序は任意であり、モジュール部３は１個以上のモジュールを有している。
ここで、アサイン部１、一括代入部４は独立の関数であっても、モジュール部３を示す関数の中に記述されていても、どちらでもよい。また、ループ部内の各部の呼び出しが、一括代入部４、アサイン部１、モジュール部３の順であってもよく、その理由は代入動作がループしているためモジュール部３の実行後の次のループの先頭で一括代入部４が実行されるので、同等の動作をするためである。
【００２０】
アサイン部２、モジュール部３における各モジュール、一括代入部４、ループ部５は、それぞれ１つずつ以上の関数で構成されており、宣言部１では各関数で用いられる変数が宣言される。関数の外部で宣言している変数はグローバル変数と呼ばれどの関数内でも使用することができる。変数は関数内で宣言してもよく、その場合はその変数はその関数内でのみ有効となり、ローカル変数と呼ばれる。本実施例でグローバル変数として宣言した理由は、シミュレータでシミュレーションするとき、グローバル変数ならすべての変数名がそのまま参照できるのでシミュレーション効率が高いためと、モジュール内で使用するときに入出力リストを作る必要がないので記述の手間が少ないというメリットがあるためである。また、デジタル回路に変換したとき接続端子となるものは単独の変数で、レジスターとなるものはレジスターのＤ入力を示す変数と、出力を示す変数の２つの変数で宣言される。
【００２１】
アサイン部２では、モジュール部３内の各モジュールで使用される組み合わせ回路（レジスターを用いない論理回路）の出力を定義しておく。モジュールに先立って定義しておく理由は、レジスターは一括代入部４で一括代入する手法を用いて、プログラム言語の記述順序の制限をなくしたが、組み合わせ回路においては定義文の後でしか使用することはできず、モジュール内で定義するとそのモジュールが呼び出されるよりも先に呼び出されるモジュール内では使用することができないため、複数のモジュールで使用される組み合わせ回路の出力の変数を先に定義しておくのである。
【００２２】
モジュール部３ではデジタル回路を合成するための具体的な処理を記述し、レジスターへの代入はＤ入力を示す変数への代入として記述する。そして、一括代入部では、すべてのレジスターのＤ入力変数をレジスター変数に代入し、ループ部５では、クロックに同期した処理のクロックに応じた動作の繰り返しを記述している。
【００２３】
図４は、本発明のデジタル回路の設計方法の第３の実施例で、複数のクロックやゲーティド・クロックを用いたＣプログラムの例の１部であり、左端の数値は説明のための何行目かを示す行番号である。
【００２４】
図４において、１行目から７行目はタイミング信号を発生させるための関数 timing() であり、 clk_cnt はクロックを分周するためのカウンターを構成するためのレジスターで、 clk_cnt_i はそのＤ入力である。この関数内では、非同期リセット時 clk_cnt を０にし、 clk_cnt が２の時０にし、それ以外の時＋１することにより３分周回路になっており、これによりループ１周のクロックとは異なる第２のクロックを発生させている。また、９行目から２１行目は一括代入部の関数 non_blocking_assignment() で、非同期リセット時は１１行目の判断で一括代入をスキップし、リセット解除時は、毎クロックで動作するレジスター clk_cnt と reg_a に毎ループ代入され、１４行目の判断で clk_cnt が０の時のみ reg_b に代入が実行されることにより３回に１回という毎ループとは異なり、複数のクロックによる動作を記述しており、また１７行目の判断で clk_halt （別のモジュールで値を設定しており、設定する部分は省略）が０の時のみ reg_c に代入し、１の時は前値ホールドするというゲーティド・クロック動作を記述しており、reg_a 、 reg_b 、 reg_c は後述の関数 xxx() 内で使用されている。また、２３行目から２９行目はループ部の関数 loop() で、前述の関数 timing() とモジュール部の関数 xxx() と、一括代入部の関数 non_blocking_assignment() がループしており、回路動作は関数 xxx() （図示せず）内に記述されている。
【００２５】
図５は、本発明のデジタル回路設計のコンパイラーの１実施例である第４の実施例のブロック図である。２１は本発明のデジタル回路設計方法に基づくＣプログラムで、例えば図１に示すプログラムであり、２２はコンピューター内のプログラムで構成された字句解析部、２３はコンピューター内のプログラムで構成された構文解析部、２４はコンピューター内のプログラムで構成されたコード生成部であり、出力されるのが２５のＨＤＬコードであり、例えば図２に示すｖｅｒｉｌｏｇ  ＨＤＬのリストをファイルとして出力するものである。
【００２６】
図５において、コンピューターに読み込まれたＣプログラム２１は字句解析部２２でトークンと呼ばれる変数や演算子の単位に分解され、構文解析部２３でトークンの意味を解析する。ここでＣプログラムの変数が、例えば xxx と xxx_i の２つの変数で構成されていればレジスターと判断し、１つの変数のみで構成されていれば接続端子と判断する。構文解析部２３で解析した結果はコード生成部２４に送られ、Ｃプログラムから verolpg HDL の文法に基づいて変換され、ＨＤＬコード２５が出力される。ここでレジスターと判断された変数はクロック同期で値が変化するラッチとして合成され、接続端子と判断された変数は組み合わせ回路を合成する。また、Ｃプログラム２１が図４のように複数のクロックまたはゲーティド・クロックを使用していると判断されたらｖｅｒｉｌｏｇ  ＨＤＬの「always@」文の中のクロック名を通常のクロックと変えて合成する。また、図２で説明したような判断・実行も行いＨＤＬコード２５を生成する。また、本実施例では、生成するデジタル回路はｖｅｒｉｌｏｇ  ＨＤＬであるが、ＬＳＩを合成するセルの接続情報を示すネットリストや回路図であってもよい。
また、本発明のデジタル回路設計のコンパイラーは、コンピュータで読みとり可能な記録媒体に記録されたコンピュータプログラムとして供給することができる。
【００２７】
図６は、本発明のデジタル回路設計のシミュレータの１実施例である第５の実施例のブロック図である。２１は本発明のデジタル回路設計方法に基づくＣプログラムで、例えば図１に示すプログラムであり、３２はコンピューター内のプログラムで構成されたＣコンパイラー部、３３はコンピューター内のプログラムで構成されたシミュレーション部、３４はコンピューター内のプログラムで構成されたシミュレーション結果の表示部である。
【００２８】
図６において、コンピューターに読み込まれたＣプログラム２１はＣコンパイラー部３２でコンピューター上で実行できる形式に変換される。例えば図１で示すＣプログラムをコンパイルして実行形式のオブジェクトコードに変換し、実行すると指定の入力ファイルからデータを読み込み、Ｃプログラムで記述されたＦＩＲフィルターを通した後のデータが指定のファイルに出力される。次にシミュレーション部３３ではオブジェクトコードを実行し、Ｃプログラム中の各変数のクロック毎の値を記憶しておき、オペレーターの指示に従って必要なデータをシミュレーション結果データとして表示部３４に引き渡す。シミュレーション部３３はデバッグに必要なブレーク・ポイント設定、指定ポイントまでの実行、ステップ実行等のデバッガー機能も有している。そして、表示部３４ではシミュレーション部３３から引き渡されたデータをオペレーターの指示に従ってグラフィック表示したり、テキスト表示をしたりする。
また、本発明のデジタル回路設計のシミュレータは、コンピュータで読みとり可能な記録媒体に記録されたコンピュータプログラムとして供給することができる。
【００２９】
【発明の効果】
以上説明したように本発明のデジタル回路設計方法は、レジスターを示す第１の変数と、レジスターの入力を示す第２の変数とに分けて記述し、モジュール部での処理の実行後に第２の変数から第１の変数に一括して代入するため、ＨＤＬに変換後の非ブロッキング代入と同じ処理が容易に記述でき、また複数のモジュールで使用する組み合わせ回路をモジュール部の実行前に実行されるように記述することによってプログラミング言語の順次処理による制約を軽減でき、複数のクロック、ゲーティド・クロック、または非同期リセット／セットに容易に対応できるという利点がある。
【００３０】
また、本発明のデジタル回路設計のコンパイラは本発明のデジタル回路設計方法に基づくＣプログラムを容易にＨＤＬ等の回路情報に変換することができ、本発明のデジタル回路設計のシミュレータは本発明のデジタル回路設計方法に基づくＣプログラムを容易にシミュレーション、デバッグすることができるという利点がある。