12.システムタスク

$xxxで、シミュレータに組み込み済みのタスクまたは、ファンクションをシステムタスク/システムファンクションといいます。Verilog2001になって、「こういうのが欲しい」というのは、大抵あります。

システムタスクの呼び出しはstatementに属します。
<system_task_enable>
::= <name_of_system_task> ;
||= <name_of_system_task> ( <expression> <,<expression>>* ) ;

一方、システムファンクションの呼び出しは、expressionに属します。

<function_call> ::= <name_of_function> ( <expression> <,<expression>>* ) ||= <name_of_system_function> ( <expression> <,<expression>>* ) ||= <name_of_system_function>

12.1 Conversion Function

12.1.1 real 系の変換ファンクションとして次があります。

ファンクション名 戻り値 機能
$realtobits [63:0] real 型を引数にして、ビットベクタに変換します。ビットベクタイメージは、IEEE Std 754-1985で、C言語のdoubleと等価です。
Verilogでは、REAL型のままポート宣言で渡すことはできません。REAL変数を他のmodule、funciton,task等に引き渡したいときにこのFunctionで変換してやります。
(下記サンプル参照)
$bitstoreal real 上記の反対です。
$itor real ビットベクタをREALに変換します。
$rtoi [31:0] REALをビットベクタに変換します。変換はC言語と同様、小数点以下は、切捨てです。

Note1:Veritak実装では、32ビットIntegerより大きい数の変換は不定となります。
Note2:Veritak実装では、32ビットIntegerより大きい数の変換は不定です。

<例>
module driver (net_r);
  output net_r;
  real r;
  wire [63:0] net_r = $realtobits (r);
endmodule

module receiver (net_r);
  input net_r;
  wire [63:0] net_r;
  real r;
  
  always @*   r = $bitstoreal (net_r);

endmodule

12.1.2 符号の変換(Verilog2001)

$signed  戻り値は、signedになります。
$unsigned 戻り値は、 unsignedになります。

<例>
 reg [7:0] regA;
 reg signed [7:0] regS;

 regA = $unsigned (-4); // regA は 4'b1100になります。
 regS = $signed (4'b1100); // regS は -4になります。

12.2 Debug Use task($display,$fdisplay,$strobe,$monitor,$fmonitor)
 

12.2.1 $display

12.2.2 $write

 次の例は、EXCEL読み込み用に、2次元メモリの内容を、コンマセパレートの10進符号付テキストファイルを書く例です。
 $writeは、$dsiplayから改行コードを除いたものです。

task save_data_to_file;
                begin
                        fi=$fopen(Eye_Save_Data_File);
                        for (i=0;i<samples_per_scan;i=i+1) begin
                                for (j=0;j< max_columns;j=j+1) begin
                                        if (j==0)               $fwrite(fi,"%d ",$signed(saved_wave[i][j]));
                                        else if (j==max_columns-1) $fdisplay(fi,", %d ",$signed(saved_wave[i][j]));
                                        else    $fwrite(fi,",%d",$signed(saved_wave[i][j]));
                                end
                        end
                        $fclose(fi);
                end
        endtask

12.2.3 $strobe
 $strobe は、その時刻の最終的な確定値(つまり、次の時刻に移る直前に値をサンプル)をモニタします。

forever @(negedge clock)
$strobe ("At time %d, data is %h",time ,data);

module strobe_test;
  reg a;
  wire b=~a;
  initial begin
      $strobe("strobing a=%b b=%b time=%t",a,b,$time);
      a=0;
      #0;
      a=1;
      $display("displaying a=%b b=%b",a,b);
  end
endmodule

実行結果です。

displaying a=1 b=1
strobing a=1 b=0 time=                   0

この性質は、継続代入文のモニタや、ASICでの提出パターンを作るときに重宝します。

12.2.4 $monitor
変化点を$displayと同じように出力します。

例です。

//Nov.16.2004 realtime variable delay regression test
//Nov.19.2004 real parameter net delay
//Feb.3.2005
`timescale 1ns/1ps
module real_delay_test;
        parameter net_real_delay=3.1;//3.345;
        
        real tp;
        reg [7:0] a,b;
        integer i;
        integer a_addr=2022,b_addr=222;
        real rdelay;
        wire [7:0] #(net_real_delay) wb=a;
        reg [7:0] mem [0:2035][0:223];


        initial begin
                        rdelay=1.1;
                        $monitor("a=%b wb=%b time=%f ",a,wb,$realtime);
                        tp=10.11;
                        i=tp;
                        b=5;
                        a<=#(tp) b;
                        #(10.110);
                        #(0.002);
                        a=8'hff;
                        #(10);
                        a=8'h00;

                        //new monitor for memory word
                        #100;
                        $monitor("new monitor1 :mem[%d][%d]=%b time=%f",a_addr,b_addr,mem[a_addr][b_addr],$realtime); 
                        for (i=0;i<8; i=i+2) begin
                                mem[a_addr][b_addr][i +:2]=2'b11;
                                #10;
                        end

                                //new monitor for memory bit on certain word 
                        #100;
                        $monitor("new monitor 2 :mem[%d][%d][7]=%b time=%f",a_addr,b_addr,mem[a_addr][b_addr][7],$realtime); 
                        for (i=0;i<8; i=i+1) begin
                                mem[a_addr][b_addr][i ]=0;
                                #10;
                        end
                        //monitor off for moment
                        $display("monitor off");
                        $monitoroff;
                        
                        for (i=0;i<8; i=i+2) begin
                                mem[a_addr][b_addr][i +:2]=2'b11;
                                #10;
                        end
                        //monitor on again
                        $monitoron;
                        $display("monitor on again");
                        for (i=0;i<8; i=i+1) begin
                                mem[a_addr][b_addr][i ]=0;
                                #10;
                        end


        end

        


endmodule



実行結果です。$monitorが発行された時刻と、その後の変化点で、出力している様子がわかります。
$monitorは、新しい$monitorが発行されるとそれまでのモニタは破棄されて、新しいmonitorのみに対応します。
$monitoroffでお休みし$monitoronで再開します。
例にあるように、メモリのあるワードのあるビットをモニタすることもできるので、便利かつ強力なデバッグ機能です。

F:\regression_test\monitor_test.v(5)::real_delay_test
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------

a=xxxxxxxx wb=xxxxxxxx time=0.000000 
a=00000101 wb=xxxxxxxx time=10.110000 
a=11111111 wb=xxxxxxxx time=10.112000 
a=11111111 wb=xxxxx1x1 time=13.210000 
a=11111111 wb=11111111 time=13.212000 
a=00000000 wb=11111111 time=20.112000 
a=00000000 wb=00000000 time=23.212000 
new monitor1 :mem[       2022][        222]=xxxxxx11 time=120.112000
new monitor1 :mem[       2022][        222]=xxxx1111 time=130.112000
new monitor1 :mem[       2022][        222]=xx111111 time=140.112000
new monitor1 :mem[       2022][        222]=11111111 time=150.112000
new monitor 2 :mem[       2022][        222][7]=1 time=260.112000
new monitor 2 :mem[       2022][        222][7]=0 time=330.112000
monitor off
monitor on again
new monitor 2 :mem[       2022][        222][7]=1 time=380.112000
new monitor 2 :mem[       2022][        222][7]=0 time=450.112000

---------- シミュレーションを終了します。time=460----------

ファイルに出力させる例です。$fmonitorは、古いmonitorは、破棄されません。$monitoron、$monitoroffは利かないので、$fmonitorを止めたいときは、$fcloseしてしまいます。

次の例は、monitorの結果をファイル(monitor.txt)にアペンドしていく例です。

//Nov.16.2004 realtime variable delay regression test
//Nov.19.2004 real parameter net delay
//Feb.3.2005
`timescale 1ns/1ps
module real_delay_test;
        parameter net_real_delay=3.1;//3.345;
        
        real tp;
        reg [7:0] a,b;
        integer i;
        integer a_addr=2022,b_addr=222;
        real rdelay;
        wire [7:0] #(net_real_delay) wb=a;
        reg [7:0] mem [0:2035][0:223];
        integer fp=1;

        initial begin :monitor
                        #0;
                        rdelay=1.1;
                        fp=$fopen("monitor.txt","a");//append mode
                        if(!fp) begin
                                $display("can not open the file \"monitor.txt \"");
                                disable monitor;//break the block
                        end
                        $fmonitor(fp,"a=%b wb=%b time=%f ",a,wb,$realtime);
                        tp=10.11;
                        i=tp;
                        b=5;
                        a<=#(tp) b;
                        #(10.110);
                        #(0.002);
                        a=8'hff;
                        #(10);
                        a=8'h00;

                        //new monitor for memory word
                        #100;
                        $fmonitor(fp,"new monitor1 :mem[%d][%d]=%b time=%f",a_addr,b_addr,mem[a_addr][b_addr],$realtime); 
                        for (i=0;i<8; i=i+2) begin
                                mem[a_addr][b_addr][i +:2]=2'b11;
                                #10;
                        end

                                //new monitor for memory bit on certain word 
                        #100;
                        $fmonitor(fp,"new monitor 2 :mem[%d][%d][7]=%b time=%f",a_addr,b_addr,mem[a_addr][b_addr][7],$realtime); 
                        for (i=0;i<8; i=i+1) begin
                                mem[a_addr][b_addr][i ]=0;
                                #10;
                        end
                        //monitor off for moment
                        $fdisplay(fp,"monitor off");//not work for fmonitor
                        $monitoroff;
                        
                        for (i=0;i<8; i=i+2) begin
                                mem[a_addr][b_addr][i +:2]=2'b11;
                                #10;
                        end
                        //monitor on again
                        $monitoron;
                        $fdisplay(fp,"monitor on again");
                        for (i=0;i<8; i=i+1) begin
                                mem[a_addr][b_addr][i ]=0;
                                #10;
                        end
                        a=8'haa;
                        $fdisplay(fp,"closing fmonitor");
                        $fclose(fp);
                        //no fmonitor is available
                        for (i=0;i<8; i=i+2) begin
                                mem[a_addr][b_addr][i +:2]=2'b11;
                                #10;
                        end
                        for (i=0;i<8; i=i+1) begin
                                mem[a_addr][b_addr][i ]=0;
                                #10;
                        end
                        
        end

        


endmodule



実行結果です。fminotor.txtの中身です。

a=xxxxxxxx wb=xxxxxxxx time=0.000000 
a=00000101 wb=xxxxxxxx time=10.110000 
a=11111111 wb=xxxxxxxx time=10.112000 
a=11111111 wb=xxxxx1x1 time=13.210000 
a=11111111 wb=11111111 time=13.212000 
a=00000000 wb=11111111 time=20.112000 
a=00000000 wb=00000000 time=23.212000 
new monitor1 :mem[       2022][        222]=xxxxxx11 time=120.112000
new monitor1 :mem[       2022][        222]=xxxx1111 time=130.112000
new monitor1 :mem[       2022][        222]=xx111111 time=140.112000
new monitor1 :mem[       2022][        222]=11111111 time=150.112000
new monitor 2 :mem[       2022][        222][7]=1 time=260.112000
new monitor1 :mem[       2022][        222]=11111110 time=260.112000
new monitor1 :mem[       2022][        222]=11111100 time=270.112000
new monitor1 :mem[       2022][        222]=11111000 time=280.112000
new monitor1 :mem[       2022][        222]=11110000 time=290.112000
new monitor1 :mem[       2022][        222]=11100000 time=300.112000
new monitor1 :mem[       2022][        222]=11000000 time=310.112000
new monitor1 :mem[       2022][        222]=10000000 time=320.112000
new monitor 2 :mem[       2022][        222][7]=0 time=330.112000
new monitor1 :mem[       2022][        222]=00000000 time=330.112000
monitor off
new monitor1 :mem[       2022][        222]=00000011 time=340.112000
new monitor1 :mem[       2022][        222]=00001111 time=350.112000
new monitor1 :mem[       2022][        222]=00111111 time=360.112000
new monitor1 :mem[       2022][        222]=11111111 time=370.112000
new monitor 2 :mem[       2022][        222][7]=1 time=370.112000
monitor on again
new monitor1 :mem[       2022][        222]=11111110 time=380.112000
new monitor1 :mem[       2022][        222]=11111100 time=390.112000
new monitor1 :mem[       2022][        222]=11111000 time=400.112000
new monitor1 :mem[       2022][        222]=11110000 time=410.112000
new monitor1 :mem[       2022][        222]=11100000 time=420.112000
new monitor1 :mem[       2022][        222]=11000000 time=430.112000
new monitor1 :mem[       2022][        222]=10000000 time=440.112000
new monitor 2 :mem[       2022][        222][7]=0 time=450.112000
new monitor1 :mem[       2022][        222]=00000000 time=450.112000
closing fmonitor

これを利用して、コンソールにだすこともできます。コンソールは、1番に割り振られています。ただし、クローズはできません。

//Nov.16.2004 realtime variable delay regression test
//Nov.19.2004 real parameter net delay
//Feb.3.2005
`timescale 1ns/1ps
module real_delay_test;
        parameter net_real_delay=3.1;//3.345;
        
        real tp;
        reg [7:0] a,b;
        integer i;
        integer a_addr=2022,b_addr=222;
        real rdelay;
        wire [7:0] #(net_real_delay) wb=a;
        reg [7:0] mem [0:2035][0:223];
        integer fp=1;

        initial begin :monitor
                        #0;
                        rdelay=1.1;
                        fp=1;//Use console
                        if(!fp) begin
                                $display("can not open the file \"monitor.txt \"");
                                disable monitor;//break the block
                        end
                        $fmonitor(fp,"a=%b wb=%b time=%f ",a,wb,$realtime);
                        tp=10.11;
                        i=tp;
                        b=5;
                        a<=#(tp) b;
                        #(10.110);
                        #(0.002);
                        a=8'hff;
                        #(10);
                        a=8'h00;

                        //new monitor for memory word
                        #100;
                        $fmonitor(fp,"new monitor1 :mem[%d][%d]=%b time=%f",a_addr,b_addr,mem[a_addr][b_addr],$realtime); 
                        for (i=0;i<8; i=i+2) begin
                                mem[a_addr][b_addr][i +:2]=2'b11;
                                #10;
                        end

                                //new monitor for memory bit on certain word 
                        #100;
                        $fmonitor(fp,"new monitor 2 :mem[%d][%d][7]=%b time=%f",a_addr,b_addr,mem[a_addr][b_addr][7],$realtime); 
                        for (i=0;i<8; i=i+1) begin
                                mem[a_addr][b_addr][i ]=0;
                                #10;
                        end
                        //monitor off for moment
                        $fdisplay(fp,"monitor off");//not work for fmonitor
                        $monitoroff;
                        
                        for (i=0;i<8; i=i+2) begin
                                mem[a_addr][b_addr][i +:2]=2'b11;
                                #10;
                        end
                        //monitor on again
                        $monitoron;
                        $fdisplay(fp,"monitor on again");
                        for (i=0;i<8; i=i+1) begin
                                mem[a_addr][b_addr][i ]=0;
                                #10;
                        end
                        a=8'haa;

        end

        


endmodule



実行結果です。

F:\regression_test\monitor_test3.v(5)::real_delay_test
Verilogのシミュレーションの準備が完了しました。スタートは,Goボタンを押してください。
------------- シミュレーションを開始します。--------------------

a=xxxxxxxx wb=xxxxxxxx time=0.000000 
a=00000101 wb=xxxxxxxx time=10.110000 
a=11111111 wb=xxxxxxxx time=10.112000 
a=11111111 wb=xxxxx1x1 time=13.210000 
a=11111111 wb=11111111 time=13.212000 
a=00000000 wb=11111111 time=20.112000 
a=00000000 wb=00000000 time=23.212000 
new monitor1 :mem[       2022][        222]=xxxxxx11 time=120.112000
new monitor1 :mem[       2022][        222]=xxxx1111 time=130.112000
new monitor1 :mem[       2022][        222]=xx111111 time=140.112000
new monitor1 :mem[       2022][        222]=11111111 time=150.112000
new monitor 2 :mem[       2022][        222][7]=1 time=260.112000
new monitor1 :mem[       2022][        222]=11111110 time=260.112000
new monitor1 :mem[       2022][        222]=11111100 time=270.112000
new monitor1 :mem[       2022][        222]=11111000 time=280.112000
new monitor1 :mem[       2022][        222]=11110000 time=290.112000
new monitor1 :mem[       2022][        222]=11100000 time=300.112000
new monitor1 :mem[       2022][        222]=11000000 time=310.112000
new monitor1 :mem[       2022][        222]=10000000 time=320.112000
new monitor 2 :mem[       2022][        222][7]=0 time=330.112000
new monitor1 :mem[       2022][        222]=00000000 time=330.112000
monitor off
new monitor1 :mem[       2022][        222]=00000011 time=340.112000
new monitor1 :mem[       2022][        222]=00001111 time=350.112000
new monitor1 :mem[       2022][        222]=00111111 time=360.112000
new monitor1 :mem[       2022][        222]=11111111 time=370.112000
new monitor 2 :mem[       2022][        222][7]=1 time=370.112000
monitor on again

new monitor1 :mem[       2022][        222]=11111110 time=380.112000
new monitor1 :mem[       2022][        222]=11111100 time=390.112000
new monitor1 :mem[       2022][        222]=11111000 time=400.112000
new monitor1 :mem[       2022][        222]=11110000 time=410.112000
new monitor1 :mem[       2022][        222]=11100000 time=420.112000
new monitor1 :mem[       2022][        222]=11000000 time=430.112000
new monitor1 :mem[       2022][        222]=10000000 time=440.112000
new monitor 2 :mem[       2022][        222][7]=0 time=450.112000
new monitor1 :mem[       2022][        222]=00000000 time=450.112000
a=10101010 wb=00000000 time=460.112000 
a=10101010 wb=10101010 time=463.212000 

---------- シミュレーションを終了します。time=463----------

12.2.5 $timeformat


文法
timeformat_task ::= $timeformat [ ( units_number , precision_number , suffix_string , minimum_field_width ) ] ;

説明
・unit_numberは、単位です。0から-15までの数字です。-6なら、1us, -9なら1ns, -12なら 1psという具合です。
・precision_number は、小数点以下の桁数 これは、あくまで表示のための桁数であって、
シミュレーション分解能を指定するものではありません。 シミュレーション分解能は 、`timescale で設定した値になります。
・suffix_string は、好きなストリング文字を書きます。なににするかは自由ですが、unit_numberを-9にしたら、"ns" もしくは "nsec"にするのがよいでしょう。

一旦設定すると$display系の%tで、指定フォーマットで出力するようになります。

<斜め文字部はVeritak Uniqueです。>
Veritakでは、nsecや、psecをKEYワードにして時刻データをエディタが判別しています。ダブルクリックで波形に飛ぶには、
以下のようなフォーマットのいずれかを使ってください。


//Reasonable formats are
//$timeformat(-9, integer,"nsec",integer);
//$timeformat(-12,integer ,"psec",integer);
//$timeformat(-6,integer,"usec",integer);
//$timeformat(-3,integer,"msec",integer);


・minimum_field_widthは、表示桁数です。
 

サンプル



実行結果




Veritak Project のダウンロード(3.39D以上)

12.3 メモリ読み込み($readmemh ,$readmemb);

$readmemhは、16進、$readmembは、2進のテキストファイル読み込みタスクです。

reg [7:0] mem[1:256];

initial $readmemh ("mem.data", mem);//start addressが書いていないときは、左address、この場合[1]から右address[256]に向かって読み取られる。
initial $readmemh ("mem.data", mem, 16);//end addressが書いていないときは、start addressから、右address[256]に向かって読み取られる。
initial $readmemh ("mem.data", mem, 128, 1);//start address  end address が書いてあるときは、start addressを始点として、end addressに向かって読み取られる。


  
12.4 FILEIO
Verilog2001では、FILEIOが強化されています。
大体、C言語のそれと同じようなイメージです。

例して次のようなテキストファイルを読んでみます。(regression folderに入っています。)

//fgets test pattern file
# comment test
@ 123 123.1423 0101111 abcd
@ 789 1.1341e2 10000111 ffef0123
@ 323 -543e-8 1001000zx00z f0e03355

このテキストファイルを読むソースは次です。

`define EOF 32'hFFFF_FFFF
//Aug.11.2004
//Test systems tasks
// fgetc, fgets,ungetc,fscanf
module fgets_test;
        integer fp;
        integer c,r;
        reg [8*120:1] buffer;
        integer num;
        real    real_value;
        reg [15:0] bin_value;
        reg [31:0] hex_value;
        initial begin
                fp = $fopen("fgets_pattern.dat","r");//Verilog 仕様は、Default "w"で開いてしまうので、"r"がないとFILEを消してしまう。
        if (fp !=0) begin
                         c = $fgetc(fp);
                         while (c !=`EOF) begin
                                        if (c=="#") begin
                                                r=$ungetc(c,fp);
                                                r=$fgets(buffer,fp);//#も表示されることの確認
                                                $display("displaying: %s %d",buffer,r);
                                        end else if (c=="@") begin
                                                r=$fscanf(fp,"%d %f %b %h\n",num,real_value,bin_value,hex_value);
                                                $display("r=%d %d %g %b %h",r,num,real_value,bin_value,hex_value);
                                        end else begin
                                                $write("%c",c);
                                        end
                                        c=$fgetc(fp);
                         end
                end
                
        end
endmodule

次の例は、$sformatを使ってCPUの逆アセンブラを作った例です。$sprintfは、Veritak Uniqueで、$sformatに同じです。

`ifdef Veritak
//Disassenblar
        reg [30*8:1] inst;
        wire [5:0] op=IR[31:26];
        wire [25:0] bra=PC+{{10{IR[15]}},IR[15:0]}*4;//+4;
        wire [4:0] rs=IR[25:21];
        wire [4:0] rt=IR[20:16];
        wire [4:0] rd=IR[15:11];
        wire [4:0] sh=IR[10:6];
        reg [5*8:1] reg_name="abcd";

     reg [30*8:1] instD1,instD2;

        function [4*8:1] get_reg_name;
                input [4:0] field;
                begin
                        case (field)
                                0: get_reg_name="$z0";
                                1: get_reg_name="$at";
                                2: get_reg_name="$v0";
                                3: get_reg_name="$v1";
                                4: get_reg_name="$a0";
                                5: get_reg_name="$a1";
                                6: get_reg_name="$a2";
                                7: get_reg_name="$a3";
                                8,9,10,11,12,13,14,15:
                                   $sprintf(get_reg_name,"$t%1d",field-8);
                                16,17,18,19,20,21,22,23,24,25: $sprintf(get_reg_name,"$s%1d",field-16);
                                26:get_reg_name="$k0";
                                27:get_reg_name="$k1";
                                28:get_reg_name="$gp";
                                29:get_reg_name="$sp";
                                30:get_reg_name="$s8";
                                31:get_reg_name="$ra";
                        endcase
                end
        endfunction

        always @(posedge clock) begin
                instD1<=inst;
                instD2<=instD1;
        end

        always @*begin:sprintf //Jan.20.2005  @ (IR,op,bra,rs,rt,rd,sh) begin :sprintf
          reg [4*8:1] rdn;//Mar.15.2005 =get_reg_name(rd);//
          reg [4*8:1] rsn;//Mar.15.2005=get_reg_name(rs);
          reg [4*8:1] rtn;//Mar.15.2005 =get_reg_name(rt);
          rdn=get_reg_name(rd); 
          rsn=get_reg_name(rs);
          rtn=get_reg_name(rt);
          case (op)
           0:   
                case (IR[5:0])
                        0: if (rd==0 && rt==0 && rs==0 ) $sprintf(inst,"nop");
                           else $sprintf(inst,"tsll %s,%s,%2d\n",rdn,rtn,sh);
                        2:
                                $sprintf(inst," srl %s,%s,%2d\n",rdn,rtn,sh);
                        
                      3:
                                $sprintf(inst," sra %s,%s,%2d\n",rdn,rtn,sh);
                        
                       4:
                                $sprintf(inst," sllv %s,%s,%s\n",rdn,rtn,rsn);
                        
                       6:
                                $sprintf(inst," srlv %s,%s,%s\n",rdn,rtn,rsn);
                        
                 7:
                        $sprintf(inst," srav %s,%s,%s\n",rdn,rtn,rsn);
                        
                 8:
                        $sprintf(inst," jr %s\n",rsn);
                        
                 9:
                        $sprintf(inst," jalr %s\n",rsn);
                        
                 12:
                        $sprintf(inst," syscall\n");
                        
                 13:
                        $sprintf(inst," break");
                        
                 16:
                        $sprintf(inst," mfhi %s\n",rdn);
                        
                 17:
                        $sprintf(inst," mthi %s\n",rsn);
                        
                 18:
                        $sprintf(inst," mflo %s\n",rdn);
                        
                 19:
                        $sprintf(inst," mtlo %s\n",rsn);
                        
                 24:
                        $sprintf(inst," mult %s,%s\n",rsn,rtn);
                        
                 25:
                        $sprintf(inst," multu %s,%s\n",rsn,rtn);
                        
                 26:
                        $sprintf(inst," div %s,%s\n",rsn,rtn);
                        
                 27:
                        $sprintf(inst," divu %s,%s\n",rsn,rtn);
                        
                 32:
                        
                        $sprintf(inst," add %s,%s,%s",rdn,rsn,rtn);
                        
                 33:
                        if(rt==0)
                                $sprintf(inst," move %s,%s\n",rdn,rsn);
                        else
                                $sprintf(inst," addu %s,%s,%s\n",rdn,rsn,rtn);
                        
                 34:
                        $sprintf(inst," sub %s,%s,%s\n",rdn,rsn,rtn);
                        
                 35:
                        $sprintf(inst," subu %s,%s,%s\n",rdn,rsn,rtn);
                        
                 36:
                        $sprintf(inst," and %s,%s,%s\n",rdn,rsn,rtn);
                        
                 37:
                        if(rt==0) 
                                $sprintf(inst," move %s,%s\n",rdn,rsn);
                         else
                                $sprintf(inst," or %s,%s,%s\n",rdn,rsn,rtn);
                        
                 38:
                        $sprintf(inst," xor %s,%s,%s\n",rdn,rsn,rtn);
                        
                 39:
                        $sprintf(inst," nor %s,%s,%s\n",rdn,rsn,rtn);
                        
                 42:
                        $sprintf(inst," slt %s,%s,%s\n",rdn,rsn,rtn);
                        
                 43:
                        $sprintf(inst," sltu %s,%s,%s\n",rdn,rsn,rtn);
                        
                default:
                        $sprintf(inst,"Unknown Func. %08h\n",IR);
                        
                
                

                endcase
            1:
                case (IR[20:16])
                 0:
                        $sprintf(inst," bltz %s,$%08h\n",rsn,bra);
                        
                 1:
                        $sprintf(inst," bgez %s,$%08h\n",rsn,bra);
                        
                 16:
                        $sprintf(inst," bltzal %s,$%08h\n",rsn,bra);
                        
                 17:
                        $sprintf(inst," bgezal %s,$%08h\n",rsn,bra);
                        
                default:
                        $sprintf(inst,"Unknown1 %08h\n",IR);
                        
                endcase
                
         2:
                $sprintf(inst," j $%08h\n",((IR*4)&32'h0ffffffc)+(PC&32'hf0000000));
                
         3:
                $sprintf(inst," jal $%08h\n",((IR*4)&32'h0ffffffc)+(PC&32'hf0000000));
                
         4:
                if(rs==0 && rt==0)
                        $sprintf(inst," bra $%08h\n",bra);
                else
                        $sprintf(inst," beq %s,%s,$%08h\n",rsn,rtn,bra);
                
         5:
                $sprintf(inst," bne %s,%s,$%08h\n",rsn,rtn,bra);
                
         6:
                $sprintf(inst," blez %s,$%08h\n",rsn,bra);
                
         7:
                $sprintf(inst," bgtz %s,$%08h\n",rsn,bra);
                
         8:
                $sprintf(inst," addi %s,%s,#$%04h\n",rtn,rsn,IR[15:0]);
                
         9:
                if(rs==0)
                        $sprintf(inst," li %s,#$%08h\n",rtn,IR[15:0]);
                else
                        $sprintf(inst," addiu %s,%s,#$%04h\n",rtn,rsn,IR[15:0]);
                
         10:
                $sprintf(inst," slti %s,%s,#$%04h\n",rtn,rsn,IR[15:0]);
                
         11:
                $sprintf(inst," sltiu %s,%s,#$%04h\n",rtn,rsn,IR[15:0]);
                
         12:
                $sprintf(inst," andi %s,%s,#$%04h\n",rtn,rsn,IR[15:0]);
                
         13:
                if(rs==0)
                        $sprintf(inst," li %s,#$%08h\n",rtn,IR[15:0]);
                else
                        $sprintf(inst," ori %s,%s,#$%04h\n",rtn,rsn,IR[15:0]);
                
         14:
                $sprintf(inst," xori %s,%s,#$%04h\n",rtn,rsn,IR[15:0]);
                
         15://load upper immediate

                        $sprintf(inst," lui %s,#$%04h",rtn,IR[15:0]);
                
         16, 17, 18, 19: begin
                if(rs>=16)
                        $sprintf(inst," cop%d $%08h\n",op&3,IR[25:0]);
                 else
                case(rsn)
                 0:
                        $sprintf(inst," mfc%d %s,%s\n",op&3,rtn,rdn);
                        
                 2:
                        $sprintf(inst," cfc%d %s,%s\n",op&3,rtn,rdn);
                        
                 4:
                        $sprintf(inst," mtc%d %s,%s\n",op&3,rtn,rdn);
                        
                 6:
                        $sprintf(inst," ctc%d %s,%s\n",op&3,rtn,rdn);
                        
                 8, 12:
                        if(rt&1)
                                $sprintf(inst," bc%dt %d,%08h\n",op&3,rs*32+rt,bra);
                         else 
                                $sprintf(inst," bc%df %d,%08h\n",op&3,rs*32+rt,bra);
                        
                        
                 default:
                        $sprintf(inst,"Unknown16 %08h\n",IR);
                 endcase
                end
         32:
                $sprintf(inst," lb %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         33:
                $sprintf(inst," lh %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         34:
                $sprintf(inst," lwl %s,$%04h(%s)\n",IR[15:0],rsn);
                
         35:
                $sprintf(inst," lw %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         36:
                $sprintf(inst," lbu %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         37:
                $sprintf(inst," lhu %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         38:
                $sprintf(inst," lwr %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         40:
                $sprintf(inst," sb %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         41:
                $sprintf(inst," sh %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         42:
                $sprintf(inst," swl %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         43:
                $sprintf(inst," sw %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         46:
                $sprintf(inst," swr %s,$%04h(%s)\n",rtn,IR[15:0],rsn);
                
         48, 49, 50, 51:
                $sprintf(inst," lwc%d %s,$%04h(%s)\n",op&3,rtn,IR[15:0],rsn);
                
         56, 57, 58, 59:
                $sprintf(inst," swc%d %s,$%04h(%s)\n",op&3,rtn,IR[15:0],rsn);
                
        default:
                $sprintf(inst,"UnknownOp %08h\n",IR);
                
        

         
        endcase
   end


`endif