Vengineerの戯言

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

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

はじめに

Xilinx Vitis の中を調べるのその15。

今回は、シナリオファイル (sim/verilog/svtb/multi_apuint_subsys_test_sequence_lib.sv) の中を覗いてみます。

シナリオファイル

ap_hs とのシナリオファイルとの違いは、body タスクの中です。

この部分は、変更なしです。

        virtual task body();
            uvm_phase starting_phase;
            virtual interface misc_interface misc_if;
            multi_apuint_reference_model refm;

この部分は、axi_pkg を使うようになりました。

            axi_pkg::axi_busdatas_master_sequence#(6, 32) axi_master_wr_control_seq;
            axi_pkg::axi_busdatas_master_sequence#(6, 32) axi_master_rd_control_seq;

ap_hs の場合は、下記のように、multi_in0 / multi_in1 用の svr_pkg を使っています。

            string file_queue_multi_in0 [$];
            integer bitwidth_queue_multi_in0 [$];

            svr_pkg::svr_master_sequence#(8) svr_port_multi_in0_seq;
            svr_pkg::svr_random_sequence#(8) svr_port_random_port_multi_in0_seq;

            string file_queue_multi_in1 [$];
            integer bitwidth_queue_multi_in1 [$];

            svr_pkg::svr_master_sequence#(8) svr_port_multi_in1_seq;
            svr_pkg::svr_random_sequence#(8) svr_port_random_port_multi_in1_seq;

            svr_pkg::svr_slave_sequence #(16) svr_port_multi_out_seq;

この部分は、変更なしです。

            if (!uvm_config_db#(multi_apuint_reference_model)::get(p_sequencer,"", "refm", refm))
                `uvm_fatal(this.get_full_name(), "No reference model")
            `uvm_info(this.get_full_name(), "get reference model by uvm_config_db", UVM_LOW)

            `uvm_info(this.get_full_name(), "body is called", UVM_LOW)
            starting_phase = this.get_starting_phase();
            if (starting_phase != null) begin
                `uvm_info(this.get_full_name(), "starting_phase not null", UVM_LOW)
                starting_phase.raise_objection(this);
            end
            else
                `uvm_info(this.get_full_name(), "starting_phase null" , UVM_LOW)

            misc_if = refm.misc_if;


            //phase_done.set_drain_time(this, 0ns);
            wait(refm.misc_if.reset === 1);
            repeat(100)         @(posedge refm.misc_if.clock);
            ->refm.misc_if.initialed_evt;
            refm.misc_if.initialed=1;
            @(posedge refm.misc_if.clock);
            refm.misc_if.initialed=0;
            @(posedge refm.misc_if.clock);

下記の部分は、axi_master_wr_control_seq と axi_master_rd_control_seq の2つのブロックになっています。axi_master_wr_control_seq では、

  • refm.mem_blk_pages_control_multi_in0.tobusdata
  • refm.mem_blk_pages_control_multi_in1.tobusdata

の順番に、AXI Read のトランザクションを投げています。

ap_hs の時は、multi_in0/multi_in1/multi_out の3つのブロックから構成されていました。

            fork
                begin
                    fork
                        begin
                            int control_page_idx_bak;
                            `uvm_create_on(axi_master_wr_control_seq, p_sequencer.control_sqr);
                            axi_master_wr_control_seq.misc_if = refm.misc_if;
                            axi_master_wr_control_seq.ap_done    = refm.ap_done_for_nexttrans   ;
                            axi_master_wr_control_seq.ap_ready   = refm.ap_ready_for_nexttrans  ;
                            axi_master_wr_control_seq.finish     = refm.finish ;
                            axi_master_wr_control_seq.isusr_delay = axi_pkg::NO_DELAY;
                            for(int i=0; i<10; i++) begin
                                logic[63:0] data64bit[$];
                                logic[32-1:0] databusbit[$];
                                data64bit.delete(); databusbit.delete();
                                axi_master_wr_control_seq.StableAxiliteNoUpdate=0;
                                refm.mem_blk_pages_control_multi_in0.tobusdata(data64bit, refm.mem_blk_pages_control_mul
ti_in0.rd_page_idx, 32);
                                foreach(data64bit[i]) databusbit[i]=data64bit[i][32-1:0];
                                axi_master_wr_control_seq.StableAxiliteNoUpdate=1;
                                axi_master_wr_control_seq.datamerge_inavg(databusbit, 0, 16, 1);
                                data64bit.delete(); databusbit.delete();
                                axi_master_wr_control_seq.StableAxiliteNoUpdate=0;
                                refm.mem_blk_pages_control_multi_in1.tobusdata(data64bit, refm.mem_blk_pages_control_mul
ti_in1.rd_page_idx, 32);
                                foreach(data64bit[i]) databusbit[i]=data64bit[i][32-1:0];
                                axi_master_wr_control_seq.StableAxiliteNoUpdate=1;
                                axi_master_wr_control_seq.datamerge_inavg(databusbit, 0, 24, 1);
                                `uvm_send(axi_master_wr_control_seq);
                                @(posedge refm.misc_if.clock); //wait address 2 rsp done
                                @(posedge refm.misc_if.clock);
                                refm.write_data_finish_control = 1;
                                `uvm_info("control data writting thread", $sformatf("%0dth(total 10): waiting for all wr
ite data finish event",i), UVM_LOW)
                                wait(refm.allaxilite_write_data_finish.triggered);
                                refm.write_data_finish_control = 0;
                        `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);
                        wait(refm.ap_done_for_nexttrans.triggered);
                        #0.01; //make sure mem incr_rd_page_idx is called first
                            end
                        end
                        begin
                            `uvm_create_on(axi_master_rd_control_seq, p_sequencer.control_sqr)
                            axi_master_rd_control_seq.misc_if = refm.misc_if;
                            axi_master_rd_control_seq.ap_done    = refm.ap_done_for_nexttrans   ;
                            axi_master_rd_control_seq.ap_ready   = refm.ap_ready_for_nexttrans  ;
                            axi_master_rd_control_seq.finish     = refm.finish ;
                            axi_master_rd_control_seq.isusr_delay = axi_pkg::NO_DELAY;
                            for(int j=0; j<10; j=j+refm.ap_done_cnt) begin
                                logic[32-1:0] databusbit[$];
                                @refm.dut2tb_ap_done;
                                axi_master_rd_control_seq.datamerge_inavg(databusbit, (1*16+32-1)/32, 32, 0);
                                    `uvm_info("axilite data read", $sformatf("%0dth(total 10) data read sequence is star
ted",j), UVM_LOW)
                                `uvm_send(axi_master_rd_control_seq);
                                @(posedge refm.misc_if.clock); //wait address 2 rdata rsp done
                                @(posedge refm.misc_if.clock);
                                refm.read_data_finish_control = 1;
                                wait(refm.allaxilite_read_data_finish.triggered);
                            end
                        end

この部分は、ちょっと変更がありますね。

                        begin
                            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;
                                fork
                                    begin
                                        @(refm.dut2tb_ap_done);
                                    end
                                    begin
                                        @(refm.dut2tb_ap_ready);
                                        #0; refm.misc_if.tb2dut_ap_start = 0;
                                    end
                                join
                            end
                        end
                        begin
                            int delay;
                            for(int j=0; j<10; j=j+refm.ap_done_cnt) begin
                                @refm.dut2tb_ap_done;
                                #0; refm.misc_if.tb2dut_ap_continue = 0;
                                @refm.ap_done_for_nexttrans;
                            end
                        end
                    join
                end

下記は、ap_hs とほぼ同じです。p_sequencer.control_sqr.stop_sequences(); が違うだけです。

                begin
                    for(int j=0; j<10; j=j+refm.ap_done_cnt) @refm.ap_done_for_nexttrans;
                    `uvm_info(this.get_full_name(), "autotb finished", UVM_LOW)
                    -> refm.finish;
                    refm.misc_if.finished = 1;
                    @(posedge refm.misc_if.clock);
                    refm.misc_if.finished = 0;
                    @(posedge refm.misc_if.clock);
                    -> refm.misc_if.finished_evt;
                end
            join_any
            repeat(5) @(posedge refm.misc_if.clock); //5 cycles delay for finish stuff. 5 is haphazard value

            p_sequencer.control_sqr.stop_sequences();
            disable fork;

            starting_phase.drop_objection(this);

        endtask

おわりに

テストシナリオでは、AXI VIP を使って、テストしているのがわかりました。

次回は、multi_in0/multi_in1 を ap_hs、multi_out を s_axilite にした時についてみていきます。