ModelSim 用 PicoBlaze ディスアセンブラ の履歴(No.4)
更新公開メモ
電気回路/HDL/ModelSim の radix define
ModelSim を用いた PicoBlaze プログラムのデバッグ†
PicoBlaze が実行中のコマンドを、数値ではなくアセンブラで表示する方法を考えてみました。
以下の手順で、こんな風にデバッグできます。
注目は instruction の部分です。
結構簡単†
やっているのは、kcpsm3 に繋いだ instruction 信号を SystemVerilog で書いた function でディスアセンブルして、表示用の変数に代入しているだけ。
思った以上に簡単でした。
kcpsm3 と instructions:
/// **** 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)
);
テストベンチ:
`include "psm_disasm.inc"
string instruction;
always @(uut.instruction)
instruction = psm_disasm(uut.instruction);
ディスアセンブラ†
インストラクションを渡すと、ディスアセンブルした結果を文字列として返す function です。
アセンブラは xilinx オリジナルの物ではなく、 よりコンパクトな pBlazIDE のものになっています。
読み替えは簡単だと思いますが、 ディスアセンブラの方を直すのもキーワードの置き換えだけなので簡単にできると思います。
psm_disasm.inc:
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: 9674 (from 2010/06/03),
today: 1,
yesterday: 0