AWS F1インスタンス HDK の勉強を続けている。
遅いながらにどうにか進めている。cl_dram_dma についてなんとなく分かってきた。
前回はアサーションを追加してAXIバスが動作していることを確認した。
次はAXIをどうにか動かすことはできないだろうか?目標としてはCLモジュール内に新しいAXIマスタを作成して内部からDRAMにアクセスできるパスを作りたい。
目標としては、以下の部分にAXIマスタを接続してDRAMにアクセスし、データをフェッチする。
- DMAでホストからデータをDDR4メモリに格納する。
- AXIマスタデータをフェッチする
- 演算し、結果を格納する。
として、例えば行列積のアクセラレータをF1インスタンス上で動作させてみたい。
まずはテストベクタを作成して、DDR4メモリに対して自由にデータを読み書きしてみよう。
test_dram_matrix テストベクタの作成
サンプルプロジェクトとしてtest_dram_dmaをコピーしてtest_dram_matrix を作成した。これは、
$readmemh
で整数行列(16×16)を2つ分、DRAMにロードする
- CLに通知し、同じ場所からデータをフェッチする(という回路を作成する)
- フェッチしたデータを使って行列積を計算し、計算結果をDRAMに格納する
というシナリオだ。
図. test_
dram_matrix の考えるシナリオ
とりあえず書きかけのコードだが、githubに開発中のものをアップロードしている。
github.com
readmemh
をしているのは以下で、16×16のデータをまずはローカルメモリに読み込む。
initial begin
$readmemh ("datasets1.txt", datasets1);
$readmemh ("datasets2.txt", datasets2);
end
次に、データをDMAでDDR4に転送する。tb.que_buffer_to_cl
、tb.hm_put_byte
、tb.start_que_to_cl
を使って転送する。
行列1はchannel0、行列1はchannel1を使って転送する。
図. 行列積のデータをホストから転送するデータパス
tb.que_buffer_to_cl(.chan(0), .src_addr(host_memory_buffer_address), .cl_addr(64'h0000_0004_0000_0000), .len(matrix_size) );
for (int i = 0 ; i < matrix_size / 4 ; i++) begin
tb.hm_put_byte(.addr(host_memory_buffer_address+0), .d(datasets1[i][ 7: 0]));
tb.hm_put_byte(.addr(host_memory_buffer_address+1), .d(datasets1[i][15: 8]));
tb.hm_put_byte(.addr(host_memory_buffer_address+2), .d(datasets1[i][23:16]));
tb.hm_put_byte(.addr(host_memory_buffer_address+3), .d(datasets1[i][31:24]));
host_memory_buffer_address+=4;
end
host_memory_buffer_address = 64'h0_0001_0000;
tb.que_buffer_to_cl(.chan(1), .src_addr(host_memory_buffer_address), .cl_addr(64'h0000_0004_0001_0000), .len(matrix_size) );
for (int i = 0 ; i < matrix_size / 4 ; i++) begin
tb.hm_put_byte(.addr(host_memory_buffer_address+0), .d(datasets2[i][ 7: 0]));
tb.hm_put_byte(.addr(host_memory_buffer_address+1), .d(datasets2[i][15: 8]));
tb.hm_put_byte(.addr(host_memory_buffer_address+2), .d(datasets2[i][23:16]));
tb.hm_put_byte(.addr(host_memory_buffer_address+3), .d(datasets2[i][31:24]));
host_memory_buffer_address+=4;
end
...
tb.start_que_to_cl(.chan(0));
tb.start_que_to_cl(.chan(1));
do begin
status[0] = tb.is_dma_to_cl_done(.chan(0));
status[1] = tb.is_dma_to_cl_done(.chan(1));
#10ns;
timeout_count++;
end while ((status != 4'hf) && (timeout_count < 4000));
次に、CLに対してデータフェッチをトリガするのは以下だ。CLバス経由で0x500のアドレスに対して1を書き込む。これをCL側のデータフェッチのトリガ信号としよう。
tb.poke(.addr(32'h0500), .data(32'h1), .size(DataSize::UINT16), .intf(AxiPort::PORT_OCL));
CL側の記述
CL側のハードウェア構成はファブリックのS1はデフォルトでTie offされており、自由に使用できる、のように書いてあるが実際にはATGのバスが接続されている。
これは取り外して良いのだろうか?とりあえず使わないのであれば外してしまってもよい気がしている。
図. 謎。sh_cl_oclから分岐したバスがなぜかS01ポートに接続されている?これは取り外してよいのだろうか?
その代わりに、空いたcl_axi_mstr_bus
に対してAXIマスタを接続した。とりあえず、DRAMのデータを書き込んだところに対してデータフェッチを行う記述だ。
図. 謎。sh_cl_oclから分岐したバスがなぜかS01ポートに接続されている?これは取り外してよいのだろうか?
case (state)
state_init: begin
if (axi_mstr_cfg_bus.wr && axi_mstr_cfg_bus.addr[ 7: 0] == 8'h00 &&
!cl_axi_mstr_bus.arvalid) begin
cl_axi_mstr_bus.arvalid <= 1'b1;
cl_axi_mstr_bus.araddr <= 64'h0000_0004_0000_0000;
cl_axi_mstr_bus.arid <= 16'b0;
cl_axi_mstr_bus.arlen <= 8'h00;
cl_axi_mstr_bus.arsize <= 3'b111;
end
if (cl_axi_mstr_bus.arvalid && cl_axi_mstr_bus.arready) begin
cl_axi_mstr_bus.arvalid <= 1'b0;
state <= state_row;
end
end
state_row: begin
cl_axi_mstr_bus.arvalid <= 1'b1;
cl_axi_mstr_bus.araddr <= 64'h0000_0004_0001_0004;
cl_axi_mstr_bus.arid <= 16'b0;
cl_axi_mstr_bus.arlen <= 8'h00;
cl_axi_mstr_bus.arsize <= 3'b010;
state <= state_col;
end
state_col: begin
if (cl_axi_mstr_bus.arready) begin
if (col_counter <= 15) begin
cl_axi_mstr_bus.arvalid <= 1'b1;
cl_axi_mstr_bus.araddr <= cl_axi_mstr_bus.araddr + 64;
state <= state_col;
col_counter <= col_counter + 6'h1;
end else begin
cl_axi_mstr_bus.arvalid <= 1'b0;
state <= state_init;
end
cl_axi_mstr_bus.arid <= 16'b0;
cl_axi_mstr_bus.arlen <= 8'h00;
cl_axi_mstr_bus.arsize <= 3'b010;
end
end
endcase
cl_axi_mstr_bus
に対するデータロガーも接続して動作を観察しておく。
always @ (negedge clk) begin
if (cl_axi_mstr_bus.awvalid & cl_axi_mstr_bus.awready) begin
$display ("%t : [cl_axi_mstr_bus AW] LEN=%d SIZE=%d ADDR=%x", $time,
cl_axi_mstr_bus.awlen, cl_axi_mstr_bus.awsize, cl_axi_mstr_bus.awaddr);
end
if (cl_axi_mstr_bus.arvalid & cl_axi_mstr_bus.arready) begin
$display ("%t : [cl_axi_mstr_bus AR] LEN=%d SIZE=%d ADDR=%x", $time,
cl_axi_mstr_bus.arlen, cl_axi_mstr_bus.arsize, cl_axi_mstr_bus.araddr);
end
if (cl_axi_mstr_bus.wvalid & cl_axi_mstr_bus.wready) begin
$display ("%t : [cl_axi_mstr_bus W] STB=%x DATA=%x", $time, cl_axi_mstr_bus.wstrb, cl_axi_mstr_bus.wdata);
end
if (cl_axi_mstr_bus.rvalid & cl_axi_mstr_bus.rready) begin
$display ("%t : [cl_axi_mstr_bus R] DATA=%x", $time, cl_axi_mstr_bus.rdata);
end
end
これで動作を見てみた。
めっちゃ時間はかかるが、どうやらちゃんとDRAMにアクセスしてデータをフェッチできたみたいだ。
[ 33462000] : Initializing buffers
[ 33462000] : starting H2C DMA channels
33474000 : [sh_cl_dma AW] LEN= 15 SIZE=6 ADDR=0000000400000000
33474000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=efe3be658f3f3b25123b5fef95d0dbf2eeee6b4b49aa9135f25b09fb79da57bd9ea0db5f4ea6d904e1ef3abb5e3cf5d888d272fbb6f7bafe70ef716ea7feef1a
33482000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=cdeb2996cebedacc06c3d8fe51fdf3420225cefba9cf9fddee6ffa0fa70bfa0febbc9e3dfb1ebaee5b0d21dee4a10ee92989facf78cd9b379abb719bcf2a0eea
33490000 : [sh_cl_dma AW] LEN= 15 SIZE=6 ADDR=0000000400010000
33494000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=2404db84ad6199a6c37abe9c7cf482e9be6d67ccd40f64cdf2e9e4c8267a7f297bd88dbca72faa04fbbed32f24e1eac3ad3cbfcc9d2ed1a050df8a68b92d4b99
33498000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=acb3f8a6a6de5ddc950d8cade9d6b9daafb96ebae1a1a4bcc8a2a24ffc9eb0f4bd38e6d75ce4703f7b0ce090d25c7e52be7d3ab7f3a5d0a93eaafe1c2db7c5cf
33506000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=43bdcf1cba9bccd0d2b8d5e6cbb3dd51fed2553af9541b01230b7fb12bacb2b4c8fcea96b23ea5b1dd4086c9ffdecb8fbfcab8ba2e6b5d99591a5c93aad1e4be
33514000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=908a71bc8e2dbc6dc818d823af24f74cb42dedb33e8cccfe42e84bde682cb56a76aa5c78a7e1b20cdb263f68a76f2ac8576cedf6dbde1ff9ccd61b8d2d2a29a3
33522000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=3db619aceddb35fddeefcb6ea8b1a6ae36ff7cb5b55fb2230eba5eea09f559b119319c8fe28ff36feb437cc792fc6498b1dbad5ae492cce7bef8aea48ff4f4ba
33530000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=59716bea2d1e4dbfc6fbb8abfaea0e16aabdc9cdfedac4eb9f3bef10a9ad4fd48b98eadd8d00eefbda36ddbddfd1cbafde8674437efc2b354fe87ac7c1083fc9
33538000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=fa8c09af8ccb49e6fb7c8e54d30be8e2a23cfe69ccbd9ccb40debf5acddbd0bafcfaae244eeca080fc4deb95d44cd9723b7fe462f7feb21cebf54e9b3c6f6beb
33546000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=a8df1175cc16bae62bec11411a14e41e532fb6f433f32d3be0cadc320942237d72afdcb1a1c33c0f6f2fa8c40000dd7bfafcf3b0aaec9cbbbaafe33c6f5e31bb
33554000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=ddd631659ffe89ea783a31c9a4bf1cdcd89ee92f5cf3acd7fae2dc1eb2abdb5d3ffdec13b8380fadefbf7eea9a67bf1bdcdefd275ae5ba8c29aaa545eda4eb4f
33562000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=26a3c6cd3fa9d0bdfbb2c08ad72de5c0ca0fd8d00bfa9bb4cef194abe7c28fc4e07029fedd9c22acfe3fa16b01cb140ec8d1e5a8caecbbdfeb9c0c0dd0faf13d
33570000 : [sh_cl_dma W] STB=ffffffffffffffff DATA=ceddd41b08ab61bded11af8bb27654fbaa4b105dc8f61b16eeaff71c19cb6b7be8ee39273ca94dcf650fdd76287ef63bdb6dd0fad249cf8c9a689401c3d5bbbe
...
[ 33732000] : starting C2H DMA channels
Writing 0xDEAD_BEEF to address 0x00000500
34762000 : [axi_mstr_cfg_bus W] ADDR=00000500
34766000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=7 ADDR=0000000400000000
34766000 : [axi_mstr_cfg_bus W] ADDR=00000500
34782000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010004
34798000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010044
34814000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010084
34830000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=00000004000100c4
34846000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010104
34862000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010144
34878000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010184
34894000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=00000004000101c4
34910000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010204
34926000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010244
34942000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010284
34958000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=00000004000102c4
34974000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010304
34986000 : [cl_axi_mstr_bus R] DATA=efe3be658f3f3b25123b5fef95d0dbf2eeee6b4b49aa9135f25b09fb79da57bd9ea0db5f4ea6d904e1ef3abb5e3cf5d888d272fbb6f7bafe70ef716ea7feef1a
34990000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010344
34994000 : [cl_axi_mstr_bus R] DATA=a622eeadfbdeae582fc8a39e30bacd0ac9daba51caadfdff7dab21b8740b152c2493f4fabeaa3bef8eaeeb3bcd7941a978ffa3fec942a985b0ce9b1de998efbf
35006000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010384
35014000 : [cl_axi_mstr_bus R] DATA=28eacbe767f7f34ff42e9a5c4de1cec44fbe9bcecc064db7fcf1a0f3b234c6d1f26cb0fdf3524d8bcdb917fbb91b4efcea83dfa8a7e5c1ebb12ce8ccdaaf6c4f
35022000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=00000004000103c4
35026000 : [cl_axi_mstr_bus R] DATA=68f25ebf12cc8f5daea31cd4bd2bc9c64cbb656cc918a8bf2afdb3e8b25cedc4c65584db1fecd041fc5a124f93babe1ecd89fcba9edd802918bd676a0ac560cc
35038000 : [cl_axi_mstr_bus AR] LEN= 0 SIZE=2 ADDR=0000000400010404
35046000 : [cl_axi_mstr_bus R] DATA=1cadddac5ca664b3740e3fd2f5caf9ae1e5fb3e99ca3d0c3b2b8a2ff100e75febb65b131e40daef7b95ab6c8f6a5d4e5fff319b6cb208f4aeaeeb108b3ff1fb4
35050000 : [cl_axi_mstr_bus R] DATA=1efd6a41ceaf3ff86fdfdbf6b5ab2b1d9258660912ebf13944cd0387bdf9eee5c67a911a7ed6887c48edde0ec87faebae3bd46dc31636a7d5b06e9af5be4787f
35058000 : [cl_axi_mstr_bus R] DATA=7cadeaa3470d2f7e3fb1dcbf0fb5ca57d492d6c238b8ffe2a2eefc8cc2dbabdfb66568e5fa704caafc31d0dc1e9ebbb327c5b21fcdf3193d5ab2b53243b1ebfc
35074000 : [cl_axi_mstr_bus R] DATA=b301cea0c9bbde7c2594f2f3b7ad0b61ac9b2bd19ca2c9c081d0ce61e6c8cc2cd2d624785a9ea4d49dd3dd5266cd1b1c3d3bc3265cd941fc361aafc26ac2edbd
35090000 : [cl_axi_mstr_bus R] DATA=0def5d1ebb3f453e61ff7ea314e1abaafb6ffcbcae48681feb742569fe267bf18b2abbb1bf1b42dbb059cdb0d8b9bd05a531e78dd7af7d31bc2e08af5ff1f365