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
|
![]() |