はじめに
2か月間、寝かしておきました。
の続きです。
Xilinx ZynqMP SoC VIP の中を調べる(その9)
DPI-C の export task の実装 です。
テストベンチ (mpsoc_tb.v) を振り返る
Xilinx ZynqMP SoC VIP の中を調べる(その2) で説明した、テストベンチ (mpsoc_tv.v) を振り返ってみます。
mpsoc_tb.v の 下記のinitial 文を変更していきます。
変更前
initial begin $display ("running the tb"); tb_ARESETn = 1'b0; repeat(20)@(posedge tb_ACLK); tb_ARESETn = 1'b1; @(posedge tb_ACLK); repeat(5) @(posedge tb_ACLK); tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.por_srstb_reset(1'b1); #200; tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.por_srstb_reset(1'b0); tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.fpga_soft_reset(32'h1); #2000 ; // This delay depends on your clock frequency. It should be at least 16 clock cycles. tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.por_srstb_reset(1'b1); tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.fpga_soft_reset(32'h0); #2000 ; //This drives the LEDs on the GPIO output tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.write_data(32'hA0000000,4, 32'hFFFFFFFF, resp); #200 tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.read_data(32'hA0000000,4, read_data, resp); #200 $display ("LEDs are toggled, observe the waveform"); //Write into the BRAM through GP0 and read back tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.write_data(32'hA0010000,4, 32'hDEADBEEF, resp); #200 tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.read_data(32'hA0010000,4,read_data,resp); #200 $display ("%t, running the testbench, data read from BRAM was 32'h%x",$time, read_data); if(read_data == 32'hDEADBEEF) begin $display ("AXI VIP Test PASSED"); end else begin $display ("AXI VIP Test FAILED"); end $display ("Simulation completed"); $stop; end
変更後
fpga_soft_reset までは同じで、その後の GPIO/GP0 の部分は、XXXマクロで ifdef/
endif で囲み動かないようにします。その後に、dpi_main() を呼ぶようにします。
initial begin $display ("running the tb"); tb_ARESETn = 1'b0; repeat(20)@(posedge tb_ACLK); tb_ARESETn = 1'b1; @(posedge tb_ACLK); repeat(5) @(posedge tb_ACLK); tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.por_srstb_reset(1'b1); #200; tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.por_srstb_reset(1'b0); tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.fpga_soft_reset(32'h1); #2000 ; // This delay depends on your clock frequency. It should be at least 16 clock cycles. tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.por_srstb_reset(1'b1); tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.fpga_soft_reset(32'h0); #2000 ; $display("Start dpi_main %t", $time); dpi_main(); $display("Finish dpi_main %t", $time); $display ("Simulation completed"); $stop; end
dpi_main は、下記のように、import です。
import "DPI-C" context task dpi_main();
また、read_data APIに対応する vip_read32、write_data API に対応する vip_write32、指定した回数クロックをウエイトする vip_nop task を下記のように追加し、DPI-C export task とします。
export "DPI-C" task vip_nop; export "DPI-C" task vip_write32; export "DPI-C" task vip_read32; task vip_nop(input int count); for(int n=0 ; n<count; n++) begin @(posedge tb_ACLK); end endtask task vip_write32(input int unsigned addr, input int unsigned data); logic [31:0] addr_r, data_r; reg resp; addr_r = addr; data_r = data; tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.write_data(addr_r, 4, data_r, resp); endtask // write task vip_read32(input int unsigned addr, output int unsigned data); logic [31:0] addr_r, data_r; reg resp; addr_r = addr; tb.mpsoc_sys.mpsoc_preset_i.zynq_ultra_ps_e_0.inst.read_data(addr_r, 4, data_r, resp); data = data_r; endtask
このファイルを mpsoc_dpi.svh とします。そして、下記のように、mpsoc_tb.v の initial 文の前で include するようにします。
//------------------------------------------------------------------------ // Simple Clock Generator //------------------------------------------------------------------------ always #10 tb_ACLK = !tb_ACLK; `include "mpsoc_dpi.svh" initial begin
これで、initial 文の最後の方で実行される dpi_main 経由で c++言語の関数 dpi_main が呼び出されるようになります。
おわりに
次回は、dpi_main の中をみてみます。
関連ブログ: