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 |