Vengineerの戯言

人生は短いけど、長いです。人生を楽しみましょう!

Xilinx Vitis の中を調べる(その19)

はじめに

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コードおよびテストベンチも変わるのがわかりました。