ModelSim 用 PicoBlaze ディスアセンブラ の履歴(No.3)
更新公開メモ
電気回路/HDL/ModelSim の radix define
ModelSim を用いた PicoBlaze プログラムのデバッグ†
PicoBlaze が実行中のコマンドを、数値ではなくアセンブラで表示する方法を考えてみました。
以下の手順で、こんな風にデバッグできます。
注目は instruction の部分です。
結構簡単†
やっているのは、kcpsm3 に繋いだ instruction 信号を SystemVerilog で書いた function でディスアセンブルして、表示用の変数に代入しているだけ。
思った以上に簡単でした。
kcpsm3 と instructions:
LANG:verilog /// **** instructions wire [9:0] pc ; reg [17:0] instruction ; reg [17:0] instructions[2**10-1:0]; always @(posedge clk) instruction <= instructions[pc]; initial $readmemh("instructions.mem", instructions, 0, 2**10-1); /// **** cpu wire [7:0] addr; wire [7:0] idata; wire [7:0] odata; wire we; kcpsm3 cpu ( .clk(clk), .reset(rst), .interrupt(0), // .interrupt_ack(ack), .address(pc), .instruction(instruction), .port_id(addr), .write_strobe(we), .out_port(odata), // .read_strobe(re), .in_port(idata) );
テストベンチ:
LANG:verilog `include "psm_disasm.inc" string instruction; always @(uut.instruction) instruction = psm_disasm(uut.instruction);
ディスアセンブラ†
インストラクションを渡すと、ディスアセンブルした結果を文字列として返す function です。
アセンブラは xilinx オリジナルの物ではなく、 よりコンパクトな pBlazIDE のものになっています。
読み替えは簡単だと思いますが、 ディスアセンブラの方を直すのもキーワードの置き換えだけなので簡単にできると思います。
psm_disasm.inc:
LANG:verilog localparam opJump = 5'b11010; localparam opCall = 5'b11000; localparam opRet = 5'b10101; localparam opLoad = 5'b00000; localparam opAnd = 5'b00101; localparam opOr = 5'b00110; localparam opXor = 5'b00111; localparam opTest = 5'b01001; localparam opAdd = 5'b01100; localparam opAddc = 5'b01101; localparam opSub = 5'b01110; localparam opSubc = 5'b01111; localparam opComp = 5'b01010; localparam opOut = 5'b10110; localparam opStore = 5'b10111; localparam opIn = 5'b00010; localparam opFetch = 5'b00011; localparam opRetIE = 17'b11100000000000001; localparam opRetID = 17'b11100000000000000; localparam opEInt = 17'b11110000000000001; localparam opDInt = 17'b11110000000000000; localparam opShift = 6'b100000; function string psm_disasm; input [17:0] inst; reg [4:0] code; string result, s; begin code = inst[17:13]; result = ""; // 通常コマンド if ( code == opLoad ) result = "LOAD"; if ( code == opAnd ) result = "AND"; if ( code == opOr ) result = "OR"; if ( code == opXor ) result = "XOR"; if ( code == opTest ) result = "TEST"; if ( code == opAdd ) result = "ADD"; if ( code == opAddc ) result = "ADDC"; if ( code == opSub ) result = "SUB"; if ( code == opSubc ) result = "SUBC"; if ( code == opComp ) result = "COMP"; if ( code == opOut ) result = "OUT"; if ( code == opStore) result = "STORE"; if ( code == opIn ) result = "IN"; if ( code == opFetch) result = "FETCH"; // 分岐 if ( code == opJump ) result = "JUMP"; if ( code == opCall ) result = "CALL"; result = {result, " "}; if ( code == opRet ) result = "RET"; // 特殊なコマンド if ( inst == opRetIE) result = "RETI ENABLE"; if ( inst == opRetID) result = "RETI DISABLE"; if ( inst == opEInt) result = "EINT"; if ( inst == opDInt) result = "DINT"; // シフト&ローテート if ( inst[17:12] == opShift && inst[7:4] == 4'b0000 ) begin case ( inst[3:0] ) 5'b1110: result = "SR0 "; 5'b1111: result = "SR1 "; 5'b1010: result = "SRX "; 5'b1000: result = "SRA "; 5'b1100: result = "RR "; 5'b0110: result = "SL0 "; 5'b0111: result = "SL1 "; 5'b0010: result = "SLX "; 5'b0000: result = "SLA "; 5'b0100: result = "RL "; endcase $sformat(s, "s%X", inst[11:8]); result = {result, s}; end if (result=="" || result==" ") begin // 未定義命令 $sformat(s, "INST $%04x", inst); result = s; end else begin // 分岐の引数 if( code == opJump || code == opCall || code == opRet ) begin if ( inst[12] != 0 ) begin if (inst[11:10] == 2'b00) result = {result, "Z"}; if (inst[11:10] == 2'b01) result = {result, "NZ"}; if (inst[11:10] == 2'b10) result = {result, "C"}; if (inst[11:10] == 2'b11) result = {result, "NC"}; if( code == opJump || code == opCall ) result = {result, ", "}; end if( code == opJump || code == opCall ) begin $sformat(s, "$%03x", inst[9:0]); result = {result, s}; end end // 通常命令の引数 if( code == opLoad || code == opAnd || code == opOr || code == opXor || code == opTest || code == opAdd || code == opAddc || code == opSub || code == opSubc || code == opComp || code == opOut || code == opStore|| code == opIn || code == opFetch ) begin $sformat(s, "s%X, ", inst[11:8]); result = {result, s}; if ( inst[12] != 0 ) begin $sformat(s, "s%X", inst[7:4]); end else begin $sformat(s, "$%02x", inst[7:0]); end result = {result, s}; end end psm_disasm = result; end endfunction
あまりちゃんとテストしていないので、動作がおかしかったら教えて下さい。
コメント†
Counter: 9283 (from 2010/06/03),
today: 3,
yesterday: 3