AWS F1インスタンス HDK の勉強を続けている。 目標としては、以下の部分にAXIマスタを接続してDRAMにアクセスし、データをフェッチする。
- DMAでホストからデータをDDR4メモリに格納する。
- AXIマスタデータをフェッチする
- 演算し、結果を格納する。
として、例えば行列積のアクセラレータをF1インスタンス上で動作させてみたい。ここまでは上手くできたのだが、計算の完了をホストに通知する方法があまりよくない。
Configurationバスにアクセスして、計算完了フラグが立っていた場合に次の計算のためのデータを流し込む。 これでは時間がかかるので、割り込みのような機能を使用したい。
- 今の方式では 1us に一度状態を読み込みに行く機構のため、あまり良くない。
while (matrix_finished == 0) begin tb.peek(.addr(`HELLO_WORLD_REG_ADDR), .data(matrix_finished), .size(DataSize::UINT16), .intf(AxiPort::PORT_OCL)); // start read & write $display ("Reading 0x%x from address 0x%x", matrix_finished, `HELLO_WORLD_REG_ADDR); #1us; end
HDKの資料を見ていると、割り込み通知のための信号が用意されている。
Interrupts
16 user interrupt source are supported. There is mapping logic that maps the user interrupts to MSI-X vectors. Mapping registers in the DMA controller map the 16 user interrupt sources to MSI-X vectors.
There are two sets of signals to generate interrupts:
This interface uses single clock pulses for the req/ack. The CL asserts (active high) cl_sh_apppf_irq_req[x] for a single clock to assert the interrupt request to the SH. The SH will respond with a single clock pulse on sh_cl_apppf_irq_ack[x] to acknowledge the interrupt. Once the CL asserts a request on a particular bit[x], it should not assert a request for the same bit[x] until it has recieved the ack for bit[x] from the SH. The CL may assert requests on other bits[y] (y!=x).
というわけで、計算が完了すると、cl_sh_apppf_irq_req
信号を使って割り込みをホストに対して通知してみる。
- hdk/cl/examples/cl_dram_matrix/design/cl_int_matrix_calc.sv:embed:cite
... logic [15: 0] w_int_input; assign w_int_input = {15'h000, matrix_calc_done}; ... lib_pipe #(.WIDTH(32), .STAGES(4)) PIPE_IN (.clk (clk), .rst_n (rst_n), .in_bus({int_trig, sh_cl_irq_ack}), .out_bus({cl_sh_irq_req, int_ack}) );
計算が完了すると、matrix_calc_done
をアサートし、割り込みポートから通知する。
これにより、ホストのテストベンチに割り込みが通知されることが確認できる。
50734000 : [cl_axi_mstr_bus R] DATA=000001530000015200000151000001500000014f0000014e0000014d0000014c0000014b0000014a000001490000014800000147000001460000014500000144 50738000 : [cl_axi_mstr_bus R] DATA=000001630000016200000161000001600000015f0000015e0000015d0000015c0000015b0000015a000001590000015800000157000001560000015500000154 50750000 : [matrix] result FIFO read 00000000000328b8 50754000 : [cl_axi_mstr_bus AW] LEN= 0 SIZE=3 ADDR=0000000400020038 50754000 : [cl_axi_mstr_bus W] STB=0000000000000000 DATA=000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000328b8 Received interrupt 0 [ 50772000] : Sending ack for interrupt 0 51206000 : [axi_mstr_cfg_bus R] ADDR=00000500 51210000 : [axi_mstr_cfg_bus R] ADDR=00000500 Reading 0x00000001 from address 0x00000500
おそらくこれは、sdk/userspace/utils/sh_dpi_tasks.c
に通知が行われている。sv_int_ack()
の部分に、さらに追加したい処理を記述する、ということかな。
void int_handler(uint32_t int_num) { // Vivado does not support svGetScopeFromName #ifdef SV_TEST #ifndef VIVADO_SIM svScope scope; scope = svGetScopeFromName("tb"); svSetScope(scope); #endif #endif cosim_printf("Sample Received interrupt %2d", int_num); #ifdef SV_TEST sv_int_ack(int_num); #endif }