9.逆アセンブラ

下図を見ると、通常のVerilog波形と違う点がお分かりでしょうか?逆アセンブラらしいStringが見えます。(この手法については、後述)instD2は、命令をフェッチした後、単純に2CLOCK遅らせたもので、それを逆アセンブルし、stringとしてストアしたものです。パイプラインには、5命令が存在しますが、EXE StageであるALUを中心に考えると分かりやすいものになります。(instD2は、2クロック遅らせたので、Fetch、Decode、ALU(EXE)のALUステージにおける命令を表しています。)

aadiu、r4、r4,#4は、r4<=r4+4という命令ですので、ALUを使うことになります。そこで、Aluのファンクションセレクトを見ると確かに、ADD,CCC,04になっています。このCCCは、r4の値、4は、命令中に含まれるIMMEDIATEの値です。ちゃんとALUの機能セレクトが働いていることがわかります。結果は、パイプラインレジスタARegに書き込まれますが、ARegの入力は、セレクタになっていて(部品の設計の項に手書きブロック図があるので参照ください。)この場合、ALUが選択されている必要があります。AReg_inputは、ALUになっていてALUの出力をARegの入力として選択していることがわかります。そして、次のクロックでCCC+4の結果、CD0が、ARegに書かれたことが分かります。以下AReg->NReg->RReg->DRegで、値がパイプラインレジスタを通過し、最終的にRAMのレジスタファイルのr4にCD0が書かれることになります。

なお、32ビットRISCなので、逆アセンブラもこんなに簡単に書けます。CISCならこうはいかないでしょう。(H8では、最長10バイトも見なければならない。)

このようにして、インストラクションを基点として、動作をWaveform上でチェックしていきます。




逆アセンブルリストは、GCCが出力してくれます。
たとえば、下記のような感じで出力してくれます。

test.exe:     file format elf32-bigmips

No symbols in "test.exe".
Disassembly of section .text:

00000000 <.text>:
   0:   3c1c0000        lui     $gp,0x0
   4:   379c0000        ori     $gp,$gp,0x0
   8:   34040000        li      $a0,0x0
   c:   34050000        li      $a1,0x0
  10:   341d0fec        li      $sp,0xfec
  14:   ac800000        sw      $zero,0($a0)
  18:   0085182a        slt     $v1,$a0,$a1
  1c:   1460fffd        bnez    $v1,0x14
  20:   24840004        addiu   $a0,$a0,4
  24:   0c000232        jal     0x8c8
  28:   341d0fec        li      $sp,0xfec
  2c:   0800000b        j       0x2c
  30:   341affff        li      $k0,0xffff
  34:   341b002e        li      $k1,0x2e
  38:   a35b0000        sb      $k1,0($k0)
  3c:   341a0001        li      $k0,0x1
  40:   401b7000        mfc0    $k1,$epc
  44:   03600008        jr      $k1
  48:   409a6000        mtc0    $k0,$status
  4c:   03e00008        jr      $ra
  50:   40846000        mtc0    $a0,$status
  54:   3405ffff        li      $a1,0xffff
  58:   03e00008        jr      $ra
  5c:   a0a40000        sb      $a0,0($a1)
  60:   3405ffff        li      $a1,0xffff
  64:   80860000        lb      $a2,0($a0)
  68:   10c00003        beqz    $a2,0x78
  6c:   24840001        addiu   $a0,$a0,1
  70:   1000fffc        b       0x64
  74:   a0a60000        sb      $a2,0($a1)
  78:   03e00008        jr      $ra
  7c:   34020000        li      $v0,0x0
  80:   90820000        lbu     $v0,0($a0)
  84:   00000000        nop
  88:   10400009        beqz    $v0,0xb0
  8c:   00401825        move    $v1,$v0




$sprintfは、当然合成ツールではサポートされないので、当該箇所を`ifdef Veritak −−− `endifで囲みます。こうすると”Veritak”は、Veritak内で暗黙に宣言されているので、Veritakシミュレータを使うときは、TRUEとして扱われます。その他の論理合成ツール等では、Falseでコンパイルされず、無用なWarningやエラーメッセージがでてきません。

ソースは、こんな感じです。

`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,"sll %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