はじめに
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 にした時についてみていきます。