はじめに
Xilinx Vitis の中を調べるのその19。
multi_in0, multi_in1, multi_out に、mode=s_axilite という pragma を追加するとどうなるかをみてみました。
pragma の追加
C++コードに対して、かきのように mode=s_axilite の pragma を4つ追加しました。
#include <ap_int.h> // void multi_apuint(ap_uint<8> *multi_in0, ap_uint<8> *multi_in1, ap_uint<16> *multi_out){ #pragma HLS PIPELINE #pragma HLS INTERFACE mode=m_axi bundle=BUS_A port=multi_in0 #pragma HLS INTERFACE mode=m_axi bundle=BUS_B port=multi_in1 #pragma HLS INTERFACE mode=m_axi bundle=BUS_C port=multi_out #pragma HLS INTERFACE mode=s_axilite port=multi_in0 #pragma HLS INTERFACE mode=s_axilite port=multi_in1 #pragma HLS INTERFACE mode=s_axilite port=multi_out #pragma HLS INTERFACE mode=s_axilite port=return *multi_out = (*multi_in0) * (*multi_in1); }
生成されたRTLコードは、つぎのようになりました。
- ap_XXX 関連信号が無くなった
- interrupt 信号が追加された
``verilog module multi_apuint ( ap_clk, ap_rst_n,
m_axi_BUS_A_XXX,
m_axi_BUS_B_YYY,
m_axi_BUS_C_ZZZ,
s_axi_control_PPP,
interrupt
);
interrupt は、下記の multi_apuint_control_s_axi モジュールから出力されています。
multi_apuint_control_s_axi #( .C_S_AXI_ADDR_WIDTH( C_S_AXI_CONTROL_ADDR_WIDTH ), .C_S_AXI_DATA_WIDTH( C_S_AXI_CONTROL_DATA_WIDTH )) control_s_axi_U( .AWVALID(s_axi_control_AWVALID), .AWREADY(s_axi_control_AWREADY), .AWADDR(s_axi_control_AWADDR), .WVALID(s_axi_control_WVALID), .WREADY(s_axi_control_WREADY), .WDATA(s_axi_control_WDATA), .WSTRB(s_axi_control_WSTRB), .ARVALID(s_axi_control_ARVALID), .ARREADY(s_axi_control_ARREADY), .ARADDR(s_axi_control_ARADDR), .RVALID(s_axi_control_RVALID), .RREADY(s_axi_control_RREADY), .RDATA(s_axi_control_RDATA), .RRESP(s_axi_control_RRESP), .BVALID(s_axi_control_BVALID), .BREADY(s_axi_control_BREADY), .BRESP(s_axi_control_BRESP), .ACLK(ap_clk), .ARESET(ap_rst_n_inv), .ACLK_EN(1'b1), .multi_in0(multi_in0), .multi_in1(multi_in1), .multi_out(multi_out), .ap_start(ap_start), .interrupt(interrupt), .ap_ready(ap_ready), .ap_done(ap_done), .ap_idle(ap_idle) );
mode=s_axiliteが無いときは、下記のようなコードになっていました。
multi_apuint_control_s_axi #( .C_S_AXI_ADDR_WIDTH( C_S_AXI_CONTROL_ADDR_WIDTH ), .C_S_AXI_DATA_WIDTH( C_S_AXI_CONTROL_DATA_WIDTH )) control_s_axi_U( .AWVALID(s_axi_control_AWVALID), .AWREADY(s_axi_control_AWREADY), .AWADDR(s_axi_control_AWADDR), .WVALID(s_axi_control_WVALID), .WREADY(s_axi_control_WREADY), .WDATA(s_axi_control_WDATA), .WSTRB(s_axi_control_WSTRB), .ARVALID(s_axi_control_ARVALID), .ARREADY(s_axi_control_ARREADY), .ARADDR(s_axi_control_ARADDR), .RVALID(s_axi_control_RVALID), .RREADY(s_axi_control_RREADY), .RDATA(s_axi_control_RDATA), .RRESP(s_axi_control_RRESP), .BVALID(s_axi_control_BVALID), .BREADY(s_axi_control_BREADY), .BRESP(s_axi_control_BRESP), .ACLK(ap_clk), .ARESET(ap_rst_n_inv), .ACLK_EN(1'b1), .multi_in0(multi_in0), .multi_in1(multi_in1), .multi_out(multi_out) );
差分は、下記の部分です。
.ap_start(ap_start),
.interrupt(interrupt),
.ap_ready(ap_ready),
.ap_done(ap_done),
.ap_idle(ap_idle)
mode=s_axilite 無の時は、ap_ready, ap_done, ap_ilde は、下記のような感じで生成していました。interrupt は存在しません。
always @ (*) begin if (((ap_enable_reg_pp0_iter15 == 1'b1) & (1'b0 == ap_block_pp0_stage0_subdone))) begin ap_done = 1'b1; end else begin ap_done = 1'b0; end end
always @ (*) begin if (((ap_start == 1'b0) & (ap_idle_pp0 == 1'b1) & (1'b1 == ap_CS_fsm_pp0_stage0))) begin ap_idle = 1'b1; end else begin ap_idle = 1'b0; end end
always @ (*) begin if (((1'b0 == ap_block_pp0_stage0_subdone) & (ap_enable_reg_pp0_iter0 == 1'b1) & (1'b1 == ap_CS_fsm_pp0_stage0))) be gin ap_ready = 1'b1; end else begin ap_ready = 1'b0; end end
# 生成されたテストベンチ sim/verilog/svtb/sv_module_top.sv は、mode=s_axilite 無しと同じです。 [f:id:Vengineer:20220710163114p:plain] sv_module_top.sv の差分は、下記の部分のみです。
26c26,28
< assign misc_if.dut2tb_ap_ready = apatb_multi_apuint_top.AESL_inst_multi_apuint.ap_ready;
assign apatb_multi_apuint_top.ap_start = misc_if.tb2dut_ap_start; assign misc_if.dut2tb_ap_done = apatb_multi_apuint_top.ap_done; assign misc_if.dut2tb_ap_ready = apatb_multi_apuint_top.ap_ready;
テストシナリオ (multi_apuint__subsys_test_sequence_lib.sv) の差分は、下記の部分のみです。 axi_master_poll_control_seqは、misc_if に対応しているっぽいです。
31d30
< axi_pkg::axi_busdatas_master_sequence#(6, 32) axi_master_poll_control_seq;
130,141c129,131
< fork
< begin
< axi_master_wr_control_seq.wr_addr_data.push_back( (1<<0)+(0<<32) );
< uvm_info("control start dut by axilite", $sformatf("%0dth(total 10): begin to set start bit",i), UVM_LOW)
<
uvm_send(axi_master_wr_control_seq);
< end
< begin
< `uvm_info("control wait for ap_ready for next trans", $sformatf("%0dth(total 10): begin to wait",i), UVM_LOW)
< wait(refm.dut2tb_ap_ready.triggered);
< #0.01; //make sure mem incr_rd_page_idx is called first
< end
< join
`uvm_info("control wait for ap_ready for next trans", $sformatf("%0dth(total 10): begin to wait",i), UVM_LOW) wait(refm.dut2tb_ap_ready.triggered); #0.01; //make sure mem incr_rd_page_idx is called first
145c135,146
< wait(refm.misc_if.tb2dut_ap_start==1);
int delay; @refm.allaxilite_write_data_finish; @(posedge refm.misc_if.clock); for(int j=0; j<10; j++) begin if(j!=0) @refm.ap_ready_for_nexttrans; #0; refm.misc_if.tb2dut_ap_start = 1; @(refm.dut2tb_ap_ready); #0; refm.misc_if.tb2dut_ap_start = 0; end end begin int delay;
147,162c148,149 < fork < forever begin <
uvm_create_on(axi_master_poll_control_seq, p_sequencer.control_sqr); < axi_master_poll_control_seq.isusr_delay = axi_pkg::NO_DELAY; < axi_master_poll_control_seq.misc_if = refm.misc_if; < axi_master_poll_control_seq.rd_addr.push_back(0); <
uvm_send(axi_master_poll_control_seq) < repeat(20) @(posedge misc_if.clock); < end < begin < `uvm_info("test finish control", $sformatf("%0dth(total 10) ap_done_for_nexttrans begin to wait",j), UVM_LOW) < @refm.dut2tb_ap_done; < end < join_any < disable fork;< repeat(18) @(posedge misc_if.clock);
@refm.dut2tb_ap_done; #0; refm.misc_if.tb2dut_ap_continue = 0;
# おわりに mode=s_axilite 有無だと、生成されるRTLコードおよびテストベンチも変わるのがわかりました。