ModelSim 用 PicoBlaze ディスアセンブラ の変更点
更新- 追加された行はこの色です。
- 削除された行はこの色です。
- 電気回路/HDL/ModelSim 用 PicoBlaze ディスアセンブラ へ行く。
- 電気回路/HDL/ModelSim 用 PicoBlaze ディスアセンブラ の差分を削除
[[公開メモ]] ~ [[電気回路/HDL/ModelSim の radix define]] #contents * Xilinx が ModelSim の無償版&廉価版の配布を中止との情報 [#t85996f6] http://marsee101.blog19.fc2.com/blog-entry-1570.html Xilinx 向けには ModelSim は敷居の高い環境になってしまいました。 * ものすごい無駄骨 [#u85c17e5] 以下の内容ですが、思いっきり車輪の再発明でした。 PicoBlaze のマニュアルの VHDL Simulation という項に、 ほぼ以下の内容と同じことが可能なコードが始めから KCPSM3 のパッケージに入っていることが書かれています。 Verilog 版でもかなり探しにくいものの、"hexcharacter" という Verilog Task として入っています。 instruction の他、フラグやそれ以外の有用な情報を見やすく表示できますので、 そちらを使うのがお勧めです。 まあ、勉強にはなりましたけどね。色々な意味で・・・(負け惜しみ) 独学だと、こういうわかりきったことを発見するまでに掛かる時間が痛いです。 * ModelSim を用いた PicoBlaze プログラムのデバッグ [#u0c14a4d] PicoBlaze が実行中のコマンドを、数値ではなくアセンブラで表示する方法を考えてみました。 以下の手順で、こんな風にデバッグできます。 &attachref(picoblaze_debug.png); 注目は instruction の部分です。 * 結構簡単 [#m7a629a1] やっているのは、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); * ディスアセンブラ [#l0b8eae6] インストラクションを渡すと、ディスアセンブルした結果を文字列として返す 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 あまりちゃんとテストしていません。~ 動作がおかしかったら教えて下さい。 * SystemVerilog のコンパイル方法 [#if52ec61] 上記コードは System Verilog のキーワードである string を使っていますので、 Verilog 2001 ではコンパイルできません。 ModelSim の verilog コンパイラである vlog に -sv というオプションを渡すことで、.v ファイルを SystemVerilog としてコンパイルしてくれるようになりますので、 そのようにして使うことを想定しています。 Xilinx ISE であれば、Simulate Behavioral Model などの文字の上で右クリックから [Process Properties] を選択し、[Other VLOG command line options] に -sv を記入するのが近道です。 * コメント [#r7b96274] #comment_kcaptcha
Counter: 9605 (from 2010/06/03),
today: 1,
yesterday: 5