Verilogの規格書を見ていたら面白い機能を見つけました。他の言語で見たことが無い機能なので紹介します。
Verilog の$fopenはCのfopenと同じように、ファイル名とファイルタイプを指定して呼び出します。戻り値multichannel descriptorはintegerで受けます。
integer fd1, fd2, fd3; fd1 = $fopen("foo.txt", "w"); fd2 = $fopen("baa.txt", "w");
ここまでは普通の言語と同じですが、Verilogではmultichannel descriptorのorを取る事ができます。
fd3 = fd1 | fd2; $fdisplay(fd3, "hello");
fd3を使った出力はfd1(foo.txt)、fd2(baa.txt)の両方に同じ値を出力します。またfd3 = fd1 | fd2 | 1;と1とのorを取ることで標準出力にも表示するようになります。ちなみにveritakでの実装を見てみるとfd1は0x00000008、fd2は00000010の値になりました。
Verilog2005の規格書(IEEE Std 1364.-2005)17.2.2 File output system tasksに例があります。この機能を使うと、各ブロックのログとシミュレーション全体のログを綺麗に書き分けることが出来ます。
integer messages, broadcast, cpu_chann, alu_chann, mem_chann; initial begin cpu_chann = $fopen("cpu.dat"); if (cpu_chann == 0) $finish; alu_chann = $fopen("alu.dat"); if (alu_chann == 0) $finish; mem_chann = $fopen("mem.dat"); if (mem_chann == 0) $finish; messages = cpu_chann | alu_chann | mem_chann; // broadcast includes standard output broadcast = 1 | messages; end
broadcastを使ったときは全てのファイルと標準出力にメッセージを出します。
$fdisplay( broadcast, "system reset at time %d", $time ); $fdisplay( messages, "Error occurred on address bus", " at time %d, address = %h", $time, address ); forever @(posedge clock) $fdisplay( alu_chann, "acc= %h f=%h a=%h b=%h", acc, f, a, b );
私はログは出すだけ出してPerlで切り分けていたのですが、この機能を使うと別にプログラムを作らなくてもよさそうです。