動作合成とC/C++/SystemC/SystemVerilogの協調設計 ―― Cynthesizerの活用事例

渋谷 貴利,内海 功朗,森 義一

tag: 半導体

技術解説 2009年7月14日

5. 検証 ~協調検証~

 協調設計を採用したことでソフトウェア処理中のいくつかの関数処理をハードウェア化するという方式を採りました.処理の流れは図4に示すようにソフトウェアによる処理とハードウェアによる処理が交互に発生します.


図4 協調設計を採用したことでソフトウェアによる処理とハードウェアによる処理が交互に発生する

 

● 協調検証にSystemVerilogのDPI機能を利用

 この一連の処理をシミュレーションで検証するためには,ソフトウェアとハードウェアを同時に動かして,それらの間で発生する情報をやり取りしなければなりません.このような検証をソフトウェアとハードウェアの協調検証といいます.ソフトウェアとハードウェアの協調検証を行うためのツールは各ベンダから出ていますが,今回,筆者らはSystemVerilogのDPI(Direct Programming Interface)という機能を使って,協調検証を実現しました(2).DPIはSystemVerilogの機能なのでSystemVerilogをサポートしているシミュレータであれば使えます.例えばVCS(米国Synopsys社)やIUS(米国Cadence Design Systems社),Questa(米国Mentor Graphics社)などです.

 今回設計したIPコアは,いくつかの制御レジスタを持ち,CPUなどのホストが制御レジスタを設定してハードウェアを起動させ,ハードウェアの処理が終了したことをステータス・レジスタや割り込みでホストに知らせます.また,このIPコアはバス・マスタになることができ,ホストと同じメモリ領域をアクセスできます.

 IPコアは,いくつかのアドレス・レジスタを持っており,これらのアドレス・レジスタにアクセスすべきメモリ領域の先頭アドレスをホストが設定することで,IPコアにアクセスすべきアドレスを知らせます.

 従ってソフトウェアとハードウェアの協調検証を実現するためには,
 

  1. CのソフトウェアからIPコアのレジスタをリード/ライトすること.
  2. CのソフトウェアとIPコアが共通のメモリ領域をリード/ライトすること.

を実現できなければいけません.

● Verilog側のシミュレーション環境

 Verilog側に図5のようなシミュレーション環境を作成します.まず必要なのはIPコアのレジスタをリード/ライトするためのバス・マスタ・モデルです.CPUのシミュレーション・モデルのような高度なものは必要なく,バスのプロトコルに従ってIPコアのレジスタにアクセスできるだけのもので構いません.


図5 Verilog側に作成したシミュレーション環境

 

 また,バスにメモリ・モデルを接続します.実際のシステムにおいてはDRAMを使用することを想定していますが,今回の協調検証環境においてはDRAMのシミュレーション・モデルである必要はなく,バスの信号をモニタしてリード/ライトのアクセスが発生したことを知ることができ,バスにリード・データを出力できさえすれば構いません.

 次にバス・マスタ・モデルにIPコアのレジスタをライトさせるためのタスク(task)を作成します.これをwrite_task(addr,data)とします.また,バス・マスタ・モデルにIPコアのレジスタをリードさせるためのtaskを作成します.これをread_task(addr)とします.このtaskを実行すると,バス・マスタ・モデルの中にリード・データが保持されるものとし,このリード・データを返すためのread_data_func()という関数も作っておきます.これらのtaskとfunctionの記述例をリスト5に示します.ただし,ライトやリードを行うバス・プロトコルは,バスによってさまざまです.ここでは省略しています.

リスト5 レジスタの読み出し/書き込みタスク


 

● ソフトウェアからIPコアのレジスタをアクセスする

 まずCのプログラムからIPコアのレジスタをリード/ライトする方法を紹介します.Cのプログラム側にハードウェアのレジスタをアクセスするための関数を用意します.これをreg_write(addr,data),reg_read(addr)とします.実際のシステムでは,これらの関数の中身はIPコアのレジスタ・アドレスにアクセスするプログラムになるのですが,ここで行う協調検証では,これらの関数の中でVerilog側のtaskとfunctionを呼び出します.

 reg_write(addr,data)が実行されたとき,Verilog側のwrite_task(addr,data)を呼び出します.reg_read(addr)が実行されたとき,Verilog側のread_task(addr)とread_data_func()を呼び出します.これらの関数の記述例をリスト6に示します.

リスト6  レジスタの読み出し/書き込み関数

 準備は以上で終わりです.後はCのプログラムの中でreg_write(addr,data)を実行すれば,Verilog側のIPコアのレジスタにライトでき,reg_read(addr)を実行すれば,Verilog側のIPコアのレジスタの内容をリードできます.

 

● ソフトとハードに同じメモリ領域をアクセスさせる

 今回のシステムの場合,ソフトウェアとハードウェアの処理は交互に行われるので,メモリ・アクセスの競合問題は発生しないのですが,Cのプログラムが使っているメモリ領域をIPコアからアクセスさせるということが一つの問題点でした.なぜなら,Cのプログラムがアクセスしているメモリ空間は,ワークステーション(またはパソコン)上のメモリ空間であり,そのアドレス管理はOSが行っています.このメモリ領域をVerilog側のIPコアからアクセスするために,OSに対して問い合わせをしなければいけないとなると話はやっかいです.しかし,SystemVerilogのDPI機能を使うと非常に簡単に実現できます(図6).


図6 協調検証環境におけるメモリの共有法

 

 まずC側に指定された論理アドレスの内容を返す関数を作成します.これをc_memory_read(addr)とします.また,指定された論理アドレスに対してライトするための関数を作成します.これをc_memory_write(addr,data)とします.

 IPコアのアドレス・レジスタに,IPコアにアクセスさせたいアドレスを設定します.例えば,配列変数aaa[100][50]に格納されているデータをIPコアにリードさせたいとしましょう.配列変数aaa[100][50]の先頭アドレスをIPコアに教えたければ,このアドレス・レジスタにaaa(すなわち,ポインタ変数)が保持している値をライトします.このときライトされた値は,物理アドレスではなく論理アドレスである,ということに注意してください.

 IPコアはこのアドレス値をもらって,バス上のメモリにアクセスします.このときバス上に出力されるアドレスはaaaが保持していた論理アドレスです.Verilog側のメモリ・モデルは,バス上の信号を監視して,自分に対するリード・アクセスが発生したら,C側の関数c_memory_read(addr)を呼び出します.そして関数の返り値,すなわちリード・データを取得したら,それをバス上に出力します.ライト・アクセスが発生した場合はC側の関数c_memory_write(addr,data)を呼び出し,C側のメモリ領域にライトしてもらいます.

 このときVerilogのシミュレーション環境内のバス上を流れているアドレス値は論理アドレスですが,実際のシステムでバス上を流れるのは物理アドレスです.つまり,バス上の振る舞いの抽象度が高いままです.今回の協調検証環境は,論理アドレスから物理アドレスへの変換処理を一切省略してしまっています.従って,この協調検証環境で正しく動いたからといって実機で正しく動くとは限らないのですが,早い段階で,かつ,簡単にソフトウェアとハードウェアを接続した検証ができる,というのは大きなメリットだと思います.

● importとexport

 C側の関数をVerilog側で使えるようにするために,関数を「import」しなければいけません.またVerilog側のtaskやfunctionをC側で使えるようにするために,taskとfunctionを「export」しなければいけません.記述はリスト7の通りです.

リスト7  System Verilog DPI機能におけるimport/export宣言

 

 Cのプログラムのmain()関数をVerilog側から呼び出したいこともあるかと思います.その場合,関数名はmain以外のものに変更する必要があります.例えばc_mainなどです.そして上記と同じように,

  import "DPI" context task c_main();

と記述しておけば,Verilog側から呼び出せます.

● SystemVerilogのDPIの効能

 SystemVerilogのDPIが提供する機能は非常にシンプルですが,シンプルであるが故に非常に使い勝手が良いと思います.これを使えばアイデア次第でさまざまな検証環境を「自分で」構築できます.「おおげさな検証環境は必要無い」,「簡単な検証環境をパッパッと作りたい」という場合に,SystemVerilogのDPIは重宝すると思います.

 SystemVerilogの詳しい仕様は,SystemVerilogのリファレンス・マニュアルや参考文献(2)を参照してください.インターネットで検索しても,DPIの使用例を見つけることができます.

 SystemVerilogのDPIを使ってハードウェアとソフトウェアの協調検証環境を構築したユーザ事例を紹介しました.ここで紹介した方法は万能ではなく,Verilog側のシステム構成によっては,いろいろな問題が発生します.

 例えばVerilog側のアドレス・バスの幅が16ビットの場合は,32ビットの論理アドレスをバス上に流せません.C側から渡された論理アドレスがバス上のほかのペリフェラルのアドレス領域と重なっていれば,メモリへのアクセスとほかのペリフェラルへのアクセスを区別できなくなってしまいます.所望の検証環境を構築するには,何かしらの工夫が必要になるでしょう.C側で細工をするかVerilog側で細工をするか,アイデアはいろいろあると思いますのでSystemVerilogのDPIをうまく使って所望の検証環境を構築してみてください.

組み込みキャッチアップ

お知らせ 一覧を見る

電子書籍の最新刊! FPGAマガジン No.12『ARMコアFPGA×Linux初体験』好評発売中

FPGAマガジン No.11『性能UP! アルゴリズム×手仕上げHDL』好評発売中! PDF版もあります

PICK UP用語

EV(電気自動車)

関連記事

EnOcean

関連記事

Android

関連記事

ニュース 一覧を見る
Tech Villageブログ

渡辺のぼるのロボコン・プロモータ日記

2年ぶりのブログ更新w

2016年10月 9日

Hamana Project

Hamana-8最終打ち上げ報告(その2)

2012年6月26日