将自动重启与邮箱搭配使用 - 2023.2 简体中文

Vitis 高层次综合用户指南 (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 简体中文

邮箱功能支持与软件应用进行半同步。邮箱是一种用于更新 HLS 设计参数的非阻塞机制。下次启动设计时,将提取通过邮箱提供的任何更新。

该设计示例使用的标量值将从软件应用进行编程,并且设计将在下一次软件调用时提取这些标量值。标量 adder1adder2 将从软件应用进行异步更新。

使用以下配置命令将 HLS 编译器配置为自动重新启动模式并启用邮箱功能:

syn.interface.s_axilite_mailbox=both
syn.interface.s_axilite_auto_restart_counter=1
syn.interface.s_axilite_sw_reset=1

这会告知本工具使用自动重新启动机制创建 IP 或内核。HLS 设计代码示例如下所示:

#define DWIDTH 32
11 
12 typedef ap_axiu<DWIDTH, 0, 0, 0> pkt;
13 
14 extern "C" {
15 void krnl_stream_vdatamover(hls::stream<pkt> &in,
16     ┆   ┆   ┆   ┆   ┆ hls::stream<pkt> &out,
17     ┆   ┆   ┆   ┆   ┆ int adder1,
18     ┆   ┆   ┆   ┆   ┆ int adder2
19     ┆   ┆   ┆   ┆   ┆ ) {
20
21 #pragma HLS interface ap_ctrl_chain port=return
22 #pragma HLS INTERFACE s_axilite port=adder2
25 #pramga  HLS port=adder1 stable
   #pramga  HLS port=adder2 stable
27 bool eos = false;
28 vdatamover:
29   do {
30     // Reading a and b streaming into packets
31     pkt t1 = in.read();
32 
33     // Packet for output
34     pkt t_out;
35 
36     // Reading data from input packet
37     ap_uint<DWIDTH> in1 = t1.data;
38 
39     // Vadd operation
40     ap_uint<DWIDTH> tmpOut = in1+adder1+adder2;
41 
42     // Setting data and configuration to output packet
43     t_out.data = tmpOut;
44     t_out.last = t1.last;
45     t_out.keep = -1; // Enabling all bytes
46 
47     // Writing packet to output stream
48     out.write(t_out);
49 
50     if (t1.last) {
51     ┆ eos = true;
52     }
53   } while (eos == false);
54

创建邮箱以更新标量值 adder1adder2

从软件应用使用 set_argwrite 方法更新设计参数,如下所示。自动重启 HLS 设计将不会自行停止,因为串流接口没有启动和停止机制。此模块必须显式停止或复位。应用代码可以使用 abort() 方法显式停止设计运行。

// add(in1, in2, nullptr, data_size)
  xrt::kernel add(device, uuid, "krnl_stream_vadd");
  xrt::bo in1(device, data_size_bytes, add.group_id(0));
  auto in1_data = in1.map<int*>();
  xrt::bo in2(device, data_size_bytes, add.group_id(1));
  auto in2_data = in2.map<int*>();
 
  // mult(in3, nullptr, out, data_size)
  xrt::kernel mult(device, uuid, "krnl_stream_vmult");
  xrt::bo in3(device, data_size_bytes, mult.group_id(0));
  auto in3_data = in3.map<int*>();
  xrt::bo out(device, data_size_bytes, mult.group_id(2));
  auto out_data = out.map<int*>();
 
 
  xrt::kernel incr(device, uuid, "krnl_stream_vdatamover");
  int adder1 = 20;  // arbitrarily chosen to be different from 0
  int adder2 = 10;  // arbitrarily chosen to be different from 0
 
  // create run objects for re-use in loop
  xrt::run add_run(add);
  xrt::run mult_run(mult);
  std::cout <<"performing never-ending mode with infinite auto restart"<<std::endl;
  auto incr_run = incr(xrt::autostart{0}, nullptr, nullptr, adder1, adder2);

// create mailbox to programatically update the incr scalar adder
  xrt::mailbox incr_mbox(incr_run);
 
  // computed expected result
  std::vector<int> sw_out_data(data_size);
 
  std::cout << " for loop started" <<std::endl;
  bool error = false;   // indicates error in any of the iterations
  for (unsigned int cnt = 0; cnt < iter; ++cnt) {
 
    
    // Create the test data and software result
    for(size_t i = 0; i < data_size; ++i) {
      in1_data[i] = static_cast<int>(i);
      in2_data[i] = 2 * static_cast<int>(i);
      in3_data[i] = static_cast<int>(i);
      out_data[i] = 0;
      sw_out_data[i] = (in1_data[i] + in2_data[i] + adder1 + adder2) * in3_data[i];
    }
 
    // sync test data to kernel
    in1.sync(XCL_BO_SYNC_BO_TO_DEVICE);
    in2.sync(XCL_BO_SYNC_BO_TO_DEVICE);
    in3.sync(XCL_BO_SYNC_BO_TO_DEVICE);
 
    // start the pipeline
    add_run(in1, in2, nullptr, data_size);
    mult_run(in3, nullptr, out, data_size);
 
    // wait for the pipeline to finish
    add_run.wait();
    mult_run.wait();
 
    // prepare for next iteration, update the mailbox with the next
    // value of 'adder'.
    incr_mbox.set_arg(2, ++adder1); // update the mailbox
    incr_mbox.set_arg(3, --adder2); // update the mailbox
 
 
    // write the mailbox content to hw, the write will not be picked
    // up until the next iteration of the pipeline (incr).
    incr_mbox.write();  // requests sync of mailbox to hw
 
 
    // sync result from device to host
    out.sync(XCL_BO_SYNC_BO_FROM_DEVICE);
 
    // compare with expected scalar adders
    for (size_t i = 0 ; i < data_size; i++) {
      if (out_data[i] != sw_out_data[i]) {
        std::cout << "error in iteration = " << cnt
                  << " expected output = " << sw_out_data[i]
                  << " observed output = " << out_data[i]
                  << " adder1 = " << adder1 - 1
                  << " adder2 = " << adder2 + 1 << '\n';
        throw std::runtime_error("result mismatch");
      }
    }
  }
        incr_run.abort();
}