Vivado HLS を使ってみた(その3) [FPGA]
ようやく対象となる関数本体を作ります。「Source」にある「rgb2ycbcr.cpp」を編集します。
まずはテストベンチの関数をそのまんまコピーして、関数名を「rgb2ycbcr」にします。浮動小数点使ってますが、気にしません。
main関数のコメントを切り替えて、この関数を使うように変更します。シミュレーション結果はもちろん変わりません。
試しにこのまま合成してみます。の前にソリューションの周波数を落とします。これは周波数が高いまま(デフォルト100MHz)だとレポート画面が横長になりすぎるから、というだけの理由です。
緑色の再生ボタン(C Synthesis)を押します。ものの10数秒で完了です。レポートファイルがこちら。
「Analysis」でデータの流れが見られます。
リソースの使われ方。
なにも指示を与えていないので、パイプライン化もされていません。レイテンシ16クロック、17クロックに1演算、となっています。浮動小数点のコアを使っているので結構大きいです、が、これで良いのだったらこのまま完成でもOK?実際にインプリを試してはいませんが、HDLは普通にできてるのでこのままでも大丈夫そうです。
とは言えさすがにナンなので、整数化してみます。
まずはテストベンチの関数をそのまんまコピーして、関数名を「rgb2ycbcr」にします。浮動小数点使ってますが、気にしません。
#include "rgb2ycbcr.h" #define dat 256 /* pow(2, dw) */ YCbCr rgb2ycbcr(RGB s) { YCbCr d; const float cY [3] = { 0.2126f, 0.7152f, 0.0722f }; const float cCb[3] = {-0.1146f, -0.3854f, 0.5000f }; const float cCr[3] = { 0.5000f, -0.4542f, -0.0458f }; const float op5 = 0.5f * dat; const float llim = 0.0f; const float ulim = (float)(dat-1); float R,G,B; float Y,Cb,Cr; R = (float)s.R; G = (float)s.G; B = (float)s.B; Y = cY [0] * R + cY [1] * G + cY [2] * B; Cb = cCb[0] * R + cCb[1] * G + cCb[2] * B + op5; Cr = cCr[0] * R + cCr[1] * G + cCr[2] * B + op5; if (Y < llim) Y = llim; if (ulim < Y ) Y = ulim; if (Cb < llim) Cb = llim; if (ulim < Cb) Cb = ulim; if (Cb < llim) Cr = llim; if (ulim < Cb) Cr = ulim; d.Y = Y; d.Cb = Cb; d.Cr = Cr; return d; }
main関数のコメントを切り替えて、この関数を使うように変更します。シミュレーション結果はもちろん変わりません。
試しにこのまま合成してみます。の前にソリューションの周波数を落とします。これは周波数が高いまま(デフォルト100MHz)だとレポート画面が横長になりすぎるから、というだけの理由です。
緑色の再生ボタン(C Synthesis)を押します。ものの10数秒で完了です。レポートファイルがこちら。
================================================================ == Vivado HLS Report for 'rgb2ycbcr' ================================================================ * Date: * Version: 2013.1 * Project: rgb2ycbcr * Solution: solution1 * Product family: zynq zynq_fpv6 * Target device: xc7z020clg484-1 ================================================================ == Performance Estimates ================================================================ + Timing (ns): * Summary: +---------+--------+----------+------------+ | Clock | Target | Estimated| Uncertainty| +---------+--------+----------+------------+ |default | 100.00| 37.63| 12.50| +---------+--------+----------+------------+ + Latency (clock cycles): * Summary: +-----+-----+-----+-----+---------+ | Latency | Interval | Pipeline| | min | max | min | max | Type | +-----+-----+-----+-----+---------+ | 16| 16| 17| 17| none | +-----+-----+-----+-----+---------+ + Detail: * Instance: N/A * Loop: N/A ================================================================ == Utilization Estimates ================================================================ * Summary: +-----------------+---------+-------+--------+-------+ | Name | BRAM_18K| DSP48E| FF | LUT | +-----------------+---------+-------+--------+-------+ |Expression | -| -| 0| 114| |FIFO | -| -| -| -| |Instance | -| 24| 2007| 5419| |Memory | -| -| -| -| |Multiplexer | -| -| -| 388| |Register | -| -| 77| -| |ShiftMemory | -| -| -| -| +-----------------+---------+-------+--------+-------+ |Total | 0| 24| 2084| 5921| +-----------------+---------+-------+--------+-------+ |Available | 280| 220| 106400| 53200| +-----------------+---------+-------+--------+-------+ |Utilization (%) | 0| 10| 1| 11| +-----------------+---------+-------+--------+-------+ + Detail: * Instance: +-------------------------------------------+----------------------------------------+---------+-------+-----+-----+ | Instance | Module | BRAM_18K| DSP48E| FF | LUT | +-------------------------------------------+----------------------------------------+---------+-------+-----+-----+ |rgb2ycbcr_fadd_32ns_32ns_32_3_full_dsp_U1 |rgb2ycbcr_fadd_32ns_32ns_32_3_full_dsp | 0| 2| 177| 385| |rgb2ycbcr_fadd_32ns_32ns_32_3_full_dsp_U2 |rgb2ycbcr_fadd_32ns_32ns_32_3_full_dsp | 0| 2| 177| 385| |rgb2ycbcr_fadd_32ns_32ns_32_3_full_dsp_U3 |rgb2ycbcr_fadd_32ns_32ns_32_3_full_dsp | 0| 2| 177| 385| |rgb2ycbcr_fcmp_32ns_32ns_1_3_U14 |rgb2ycbcr_fcmp_32ns_32ns_1_3 | 0| 0| 66| 239| |rgb2ycbcr_fcmp_32ns_32ns_1_3_U15 |rgb2ycbcr_fcmp_32ns_32ns_1_3 | 0| 0| 66| 239| |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp_U4 |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp | 0| 3| 128| 320| |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp_U5 |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp | 0| 3| 128| 320| |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp_U6 |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp | 0| 3| 128| 320| |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp_U7 |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp | 0| 3| 128| 320| |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp_U8 |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp | 0| 3| 128| 320| |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp_U9 |rgb2ycbcr_fmul_32ns_32ns_32_3_max_dsp | 0| 3| 128| 320| |rgb2ycbcr_fptoui_32ns_64_3_U10 |rgb2ycbcr_fptoui_32ns_64_3 | 0| 0| 160| 414| |rgb2ycbcr_fptoui_32ns_64_3_U11 |rgb2ycbcr_fptoui_32ns_64_3 | 0| 0| 160| 414| |rgb2ycbcr_uitofp_64ns_32_3_U12 |rgb2ycbcr_uitofp_64ns_32_3 | 0| 0| 128| 519| |rgb2ycbcr_uitofp_64ns_32_3_U13 |rgb2ycbcr_uitofp_64ns_32_3 | 0| 0| 128| 519| +-------------------------------------------+----------------------------------------+---------+-------+-----+-----+ |Total | | 0| 24| 2007| 5419| +-------------------------------------------+----------------------------------------+---------+-------+-----+-----+ * Memory: N/A * FIFO: N/A * Shift register: N/A * Expression: +------------------+----------+-------+---+----+------------+------------+ | Variable Name | Operation| DSP48E| FF| LUT| Bitwidth P0| Bitwidth P1| +------------------+----------+-------+---+----+------------+------------+ |Cb_1_fu_246_p3 | Select | 0| 0| 32| 1| 1| |Cb_2_fu_272_p3 | Select | 0| 0| 32| 1| 31| |Y_1_fu_236_p3 | Select | 0| 0| 32| 1| 1| |agg_result_Cr_V | Select | 0| 0| 8| 1| 8| |agg_result_Y_V | Select | 0| 0| 8| 1| 2| |tmp_22_fu_291_p2 | or | 0| 0| 2| 1| 1| +------------------+----------+-------+---+----+------------+------------+ |Total | | 0| 0| 114| 6| 44| +------------------+----------+-------+---+----+------------+------------+ * Multiplexer: +-------------------+----+-----------+-----+-----------+ | Name | LUT| Input Size| Bits| Total Bits| +-------------------+----+-----------+-----+-----------+ |grp_fu_105_p0 | 32| 2| 32| 64| |grp_fu_105_p1 | 13| 2| 13| 26| |grp_fu_111_p1 | 10| 2| 10| 20| |grp_fu_141_p0 | 32| 2| 32| 64| |grp_fu_148_p0 | 8| 2| 8| 16| |grp_fu_161_opcode | 2| 2| 2| 4| |grp_fu_161_p0 | 32| 4| 32| 128| |grp_fu_161_p1 | 10| 2| 10| 20| |grp_fu_168_opcode | 2| 2| 2| 4| |grp_fu_168_p0 | 32| 2| 32| 64| |grp_fu_168_p1 | 10| 2| 10| 20| |grp_fu_80_p0 | 32| 3| 32| 96| |grp_fu_80_p1 | 32| 3| 32| 96| |grp_fu_84_p0 | 32| 3| 32| 96| |grp_fu_84_p1 | 32| 3| 32| 96| |grp_fu_88_p0 | 32| 2| 32| 64| |grp_fu_88_p1 | 32| 2| 32| 64| |grp_fu_99_p1 | 13| 2| 13| 26| +-------------------+----+-----------+-----+-----------+ |Total | 388| 42| 388| 968| +-------------------+----+-----------+-----+-----------+ * Register: +----------------+----+-----+-----------+ | Name | FF | Bits| Const Bits| +----------------+----+-----+-----------+ |Cb_1_reg_348 | 32| 32| 0| |ap_CS_fsm | 5| 5| 0| |reg_201 | 32| 32| 0| |tmp_25_reg_354 | 8| 8| 0| +----------------+----+-----+-----------+ |Total | 77| 77| 0| +----------------+----+-----+-----------+ ================================================================ == Interface ================================================================ * Summary: +------------------------+-----+-----+------------+-----------------+--------------+ | RTL Ports | Dir | Bits| Protocol | Source Object | C Type | +------------------------+-----+-----+------------+-----------------+--------------+ |ap_clk | in | 1| ap_ctrl_hs | rgb2ycbcr | return value | |ap_rst | in | 1| ap_ctrl_hs | rgb2ycbcr | return value | |ap_start | in | 1| ap_ctrl_hs | rgb2ycbcr | return value | |ap_done | out | 1| ap_ctrl_hs | rgb2ycbcr | return value | |ap_idle | out | 1| ap_ctrl_hs | rgb2ycbcr | return value | |ap_ready | out | 1| ap_ctrl_hs | rgb2ycbcr | return value | |agg_result_Y_V | out | 8| ap_vld | agg_result_Y_V | pointer | |agg_result_Y_V_ap_vld | out | 1| ap_vld | agg_result_Y_V | pointer | |agg_result_Cb_V | out | 8| ap_vld | agg_result_Cb_V | pointer | |agg_result_Cb_V_ap_vld | out | 1| ap_vld | agg_result_Cb_V | pointer | |agg_result_Cr_V | out | 8| ap_vld | agg_result_Cr_V | pointer | |agg_result_Cr_V_ap_vld | out | 1| ap_vld | agg_result_Cr_V | pointer | |s_R_V | in | 8| ap_none | s_R_V | scalar | |s_G_V | in | 8| ap_none | s_G_V | scalar | |s_B_V | in | 8| ap_none | s_B_V | scalar | +------------------------+-----+-----+------------+-----------------+--------------+
「Analysis」でデータの流れが見られます。
リソースの使われ方。
なにも指示を与えていないので、パイプライン化もされていません。レイテンシ16クロック、17クロックに1演算、となっています。浮動小数点のコアを使っているので結構大きいです、が、これで良いのだったらこのまま完成でもOK?実際にインプリを試してはいませんが、HDLは普通にできてるのでこのままでも大丈夫そうです。
とは言えさすがにナンなので、整数化してみます。
Vivado HLS を使ってみた(その2) [FPGA]
まずテストプログラムを作ってしまいます。ごく普通にC/C++で書いていきます。
(tab=4をスペースに置換してるので崩れてます)
I/Oポートのデータ幅を決めておきたいので、そこだけ特別な記述が入ります。
前の記事の通り、題材はRGB→YCbCr変換。実はVivado HLSには画像のためのパッケージも入っていて、RGBとかYCbCrなどの型がすでに宣言されていますが、今回は使わずに全部自分で書いてみます。
ヘッダ。「Source」を右クリックして「rgb2ycbcr.h」というファイル名で追加。
※これは後から気づいたことですが、dwはマクロじゃ無くてテンプレートで与えるべきでしょうね。
テストベンチ。「TestBench」を右クリックして「test01.cpp」というファイル名で追加。
BMPファイルを読み込んで、変換して、BMPに保存します。実行パスが「.\rgb2ycbcr\solution1\csim\build\csim.exe」という深いところにできるので画像へのパスが長めに…(笑)
RGB→YCbCr変換はWikiに書いてある方法そのままです。ついでに画像を元に戻すYCbCr→RGBの逆変換関数も用意します。けど、なにも工夫してません。ちゃんと精度のこと考えてないので、正確でもありません。エラーチェックもろくしていない全くもっていい加減なプログラム。まぁだいたい見た目が似てればよいや、的な作りです。
後でmainでコメントアウトしているrgb2ycbcrとref_rgb2ycbcrを入れ替えてテストします。
とりあえずこのまま実行してみます。「Run C Simulation」をポチ。
デフォルトのまま実行開始。
こんな画像が出てきます。(※So-netブログはBMPダメ)。
左から、元画像、Y、Cb、Cr、BGR=CbYCrに置き換え、逆変換した画像
実行環境ができたので、ハードウェアになる対象の関数を記述していきます。
(tab=4をスペースに置換してるので崩れてます)
I/Oポートのデータ幅を決めておきたいので、そこだけ特別な記述が入ります。
前の記事の通り、題材はRGB→YCbCr変換。実はVivado HLSには画像のためのパッケージも入っていて、RGBとかYCbCrなどの型がすでに宣言されていますが、今回は使わずに全部自分で書いてみます。
ヘッダ。「Source」を右クリックして「rgb2ycbcr.h」というファイル名で追加。
#define dw 8 #include <ap_int.h> struct RGB { ap_uint<dw> R,G,B; }; struct YCbCr { ap_uint<dw> Y,Cb,Cr; }; YCbCr rgb2ycbcr(RGB s);「ap_uint<n>」が「nビットの符号無し整数」という型で、これがI/Oのデータ幅になります。SystemCの「sc_uint<>」とだいたい同じでしょう。「rgb2ycbcr」がハードウェアになる関数です。
※これは後から気づいたことですが、dwはマクロじゃ無くてテンプレートで与えるべきでしょうね。
テストベンチ。「TestBench」を右クリックして「test01.cpp」というファイル名で追加。
#include <fstream> #include <iostream> #include <iomanip> #include <cstdlib> using namespace std; #include "rgb2ycbcr.h" #define dat 256 /* pow(2, dw) */ //////////////////////////// // // Y = ( 0.2126R + 0.7152G + 0.0722B) // Cb = (-0.1146R - 0.3854G + 0.5000B) + 0.5 // Cr = ( 0.5000R - 0.4542G - 0.0458B) + 0.5 // YCbCr ref_rgb2ycbcr(RGB s) { YCbCr d; const float cY [3] = { 0.2126f, 0.7152f, 0.0722f }; const float cCb[3] = {-0.1146f, -0.3854f, 0.5000f }; const float cCr[3] = { 0.5000f, -0.4542f, -0.0458f }; const float op5 = 0.5f * dat; const float llim = 0.0f; const float ulim = (float)(dat-1); float R,G,B; float Y,Cb,Cr; R = (float)s.R; G = (float)s.G; B = (float)s.B; Y = cY [0] * R + cY [1] * G + cY [2] * B; Cb = cCb[0] * R + cCb[1] * G + cCb[2] * B + op5; Cr = cCr[0] * R + cCr[1] * G + cCr[2] * B + op5; if (Y < llim) Y = llim; if (ulim < Y ) Y = ulim; if (Cb < llim) Cb = llim; if (ulim < Cb) Cb = ulim; if (Cb < llim) Cr = llim; if (ulim < Cb) Cr = ulim; d.Y = Y; d.Cb = Cb; d.Cr = Cr; return d; } //////////////////////////// // // R = Y + 1.5748(Cr-0.5) // G = Y - 0.1873(Cb-0.5) - 0.4681(Cr-0.5) // B = Y + 1.8556(Cb-0.5) // // R = Y + 1.5748Cr - 0.7874 // G = Y - 0.1873Cb - 0.4681Cr + 0.3277 // B = Y + 1.8556Cb - 0.9278 // RGB ref_ycbcr2rgb(YCbCr s) { RGB d; const float cR[3] = { 0.0000f, 1.5748f, -0.7874f * dat }; const float cG[3] = {-0.1873f, -0.4681f, 0.3277f * dat }; const float cB[3] = { 1.8556f, 0.0000f, -0.9278f * dat }; const float llim = 0.0f; const float ulim = (float)(dat-1); float R,G,B; float Y,Cb,Cr; Y = (float)s.Y; Cb = (float)s.Cb; Cr = (float)s.Cr; R = Y + cR[1] * Cr + cR[2]; G = Y + cG[0] * Cb + cG[1] * Cr + cG[2]; B = Y + cB[0] * Cb + cB[2]; if (R < llim) R = llim; if (ulim < R) R = ulim; if (G < llim) G = llim; if (ulim < G) G = ulim; if (B < llim) B = llim; if (ulim < B) B = ulim; d.R = R; d.G = G; d.B = B; return d; } #define dpath "../../../../" const char ifname[]= dpath "H-IIA-F13.bmp"; const char ofname[]= dpath "out.bmp"; const char ofnameRGB[]= dpath "outRGB.bmp"; const char ofnameY[]= dpath "outY.bmp"; const char ofnameCb[]= dpath "outCb.bmp"; const char ofnameCr[]= dpath "outCr.bmp"; #pragma pack(1) struct BITMAPFILEHEADER { char bfType[2]; // "BM" unsigned int bfSize; // File Size (Byte) unsigned short bfReserved1; // unsigned short bfReserved2; // unsigned int bfOffBits; // Image Offset }; #pragma pack(0) #pragma pack(1) struct BGR { unsigned char B,G,R; }; #pragma pack(0) int main() { ifstream ifile; ofstream ofile; ofstream ofileRGB; ofstream ofileY; ofstream ofileCb; ofstream ofileCr; BITMAPFILEHEADER bf; int imgsize; RGB src; YCbCr des; ifile.open(ifname, ios::binary); ofile.open(ofname, ios::binary); ofileRGB.open(ofnameRGB, ios::binary); ofileY.open(ofnameY, ios::binary); ofileCb.open(ofnameCb, ios::binary); ofileCr.open(ofnameCr, ios::binary); // bf ifile.read((char*)&bf, sizeof(bf)); cout << "bfType : " << bf.bfType[0] << bf.bfType[1] << endl; cout << "bfSize : " << bf.bfSize << endl; cout << "bfOffBits : " << bf.bfOffBits << endl; // copy header ofile.write((char*)&bf, sizeof(bf)); ofileRGB.write((char*)&bf, sizeof(bf)); ofileY.write((char*)&bf, sizeof(bf)); ofileCb.write((char*)&bf, sizeof(bf)); ofileCr.write((char*)&bf, sizeof(bf)); for (int i = sizeof(bf); i < bf.bfOffBits; i++) { char tch; ifile.read(&tch, sizeof(tch)); ofile.write(&tch, sizeof(tch)); ofileRGB.write(&tch, sizeof(tch)); ofileY.write(&tch, sizeof(tch)); ofileCb.write(&tch, sizeof(tch)); ofileCr.write(&tch, sizeof(tch)); } // copy imgsize = bf.bfSize - bf.bfOffBits; for (int i = 0; i < imgsize; i+=3) { BGR ipx, opx; ifile.read((char*)&ipx, sizeof(ipx)); src.R = ipx.R; src.G = ipx.G; src.B = ipx.B; des = ref_rgb2ycbcr(src); // des = rgb2ycbcr(src); opx.R = des.Y; opx.B = des.Y; opx.G = des.Y; ofileY.write((char*)&opx, sizeof(opx)); opx.R = des.Cb; opx.B = des.Cb; opx.G = des.Cb; ofileCb.write((char*)&opx, sizeof(opx)); opx.R = des.Cr; opx.B = des.Cr; opx.G = des.Cr; ofileCr.write((char*)&opx, sizeof(opx)); opx.R = des.Cr; opx.B = des.Cb; opx.G = des.Y; ofile.write((char*)&opx, sizeof(opx)); src = ref_ycbcr2rgb(des); opx.R = src.R; opx.G = src.G; opx.B = src.B; ofileRGB.write((char*)&opx, sizeof(opx)); } ifile.close(); ofile.close(); ofileRGB.close(); ofileY.close(); ofileCb.close(); ofileCr.close(); cout << "done\n"; }
BMPファイルを読み込んで、変換して、BMPに保存します。実行パスが「.\rgb2ycbcr\solution1\csim\build\csim.exe」という深いところにできるので画像へのパスが長めに…(笑)
RGB→YCbCr変換はWikiに書いてある方法そのままです。ついでに画像を元に戻すYCbCr→RGBの逆変換関数も用意します。けど、なにも工夫してません。ちゃんと精度のこと考えてないので、正確でもありません。エラーチェックもろくしていない全くもっていい加減なプログラム。まぁだいたい見た目が似てればよいや、的な作りです。
後でmainでコメントアウトしているrgb2ycbcrとref_rgb2ycbcrを入れ替えてテストします。
とりあえずこのまま実行してみます。「Run C Simulation」をポチ。
デフォルトのまま実行開始。
こんな画像が出てきます。(※So-netブログはBMPダメ)。
左から、元画像、Y、Cb、Cr、BGR=CbYCrに置き換え、逆変換した画像
実行環境ができたので、ハードウェアになる対象の関数を記述していきます。
Vivado HLS を使ってみた(その1) [FPGA]
またご無沙汰です。
最近、ZedBoardとこれ
http://avnet.co.jp/design/kits/xilinx/AES-FMC-IMAGEON-V2000C-G.aspx
入手しました。OnSemiのこのセンサーはFullHD 100fpsというセンサーですが、256x256 1700fpsで使ってみたいです。ちょっとした中速度撮影カメラですね。BayerパターンのRAW出力なので後処理は必要です。
また、Allowから低価格CycloneV SOCのSoCKitが発表されました。
http://www.arrownac.com/solutions/sockit/
DDR3がARMコアとFPGAハードマクロに1GBずつ2系統ってことでしょうか。DS5の扱いがどうなるかによりますが使ってみたいです。HSMCに上記のイメージセンサーつなぎたいな~
まぁ、この辺はおいおい。
さて、これまた最近、Xilinx VivadoのHLSに触れる機会がありました。その昔AutoESLと呼ばれてたC/C++→HDLツールです。もっと効率よい方法があるかもしれませんが、試行錯誤しながら使ってみます。参考資料はこれ。
http://www.xilinx.com/support/documentation/sw_manuals/xilinx2012_2/ug902-vivado-high-level-synthesis.pdf (PDF)
あと、サンプル記述の例が埋め込まれているので、それも参考になります。
起動画面。
「Create New Project」で新しくプロジェクト作成します。
題材としてRGB→YCbCr変換。IPはどこにでもあるので自分で作る必要は無いんですが、結果がわかっているので試すにはよろしかろうと。
ソースファイルの追加。「Top Function」で指定した関数から下がハードウェアに変換されます。
ここでちょっと違和感。ファイルを追加しないと次にいけないんですが、まだプロジェクトフォルダが作成されていないので、ファイルの場所が?今回の場合
c:\work\hls_test\rgb2ycbcr
フォルダにファイルを入れるような気がするんですが、この時点で「rgb2ycbcr」は無いため、「hls_test」に作ることになります。後でファイルの場所を変えれば良いだけですが…想定されてる使い方が違うのかな?
テストベンチ。あとで。
「ソリューション」と呼ばれる、回路生成の設定画面。
コンパイラオプションセットみたいな感じです。速度とかデバイスを指定します。これは後で変更可能ですし、複数のソリューションを用意することもできます。
今回はZedBoardを想定してZynq7020を設定。速度はデフォルト。
設定後。あ、デバイス間違えてるw
設定完了後の画面。ここにテストベンチとか追加して行きます。
使い方はほぼEclipseのままです。
上のメニューとかボタン。
緑の再生ボタンがHDL生成。その左がC/C++シミュレーション。この二つをよく使います。
Debug、Synthesis、Analysisはパースペクティブの切り替え。Debugは普通のCデバッガです。Analysisがハードウェアのデータの流れを解析するツールになります。
ここからソースを記述していきます。順番として
・テストベンチ作成。リファレンスとなるデータの読み書きを行うプログラムを書きます。
・ハードウェアになる対象の関数を作成。
・対象の関数を最適化。しなくても良いかも。
・ディレクティブ(指示子?)追加。I/Oの種類とかパイプラインとか。
てな感じで行きます。
最近、ZedBoardとこれ
http://avnet.co.jp/design/kits/xilinx/AES-FMC-IMAGEON-V2000C-G.aspx
入手しました。OnSemiのこのセンサーはFullHD 100fpsというセンサーですが、256x256 1700fpsで使ってみたいです。ちょっとした中速度撮影カメラですね。BayerパターンのRAW出力なので後処理は必要です。
また、Allowから低価格CycloneV SOCのSoCKitが発表されました。
http://www.arrownac.com/solutions/sockit/
DDR3がARMコアとFPGAハードマクロに1GBずつ2系統ってことでしょうか。DS5の扱いがどうなるかによりますが使ってみたいです。HSMCに上記のイメージセンサーつなぎたいな~
まぁ、この辺はおいおい。
さて、これまた最近、Xilinx VivadoのHLSに触れる機会がありました。その昔AutoESLと呼ばれてたC/C++→HDLツールです。もっと効率よい方法があるかもしれませんが、試行錯誤しながら使ってみます。参考資料はこれ。
http://www.xilinx.com/support/documentation/sw_manuals/xilinx2012_2/ug902-vivado-high-level-synthesis.pdf (PDF)
あと、サンプル記述の例が埋め込まれているので、それも参考になります。
起動画面。
「Create New Project」で新しくプロジェクト作成します。
題材としてRGB→YCbCr変換。IPはどこにでもあるので自分で作る必要は無いんですが、結果がわかっているので試すにはよろしかろうと。
ソースファイルの追加。「Top Function」で指定した関数から下がハードウェアに変換されます。
ここでちょっと違和感。ファイルを追加しないと次にいけないんですが、まだプロジェクトフォルダが作成されていないので、ファイルの場所が?今回の場合
c:\work\hls_test\rgb2ycbcr
フォルダにファイルを入れるような気がするんですが、この時点で「rgb2ycbcr」は無いため、「hls_test」に作ることになります。後でファイルの場所を変えれば良いだけですが…想定されてる使い方が違うのかな?
テストベンチ。あとで。
「ソリューション」と呼ばれる、回路生成の設定画面。
コンパイラオプションセットみたいな感じです。速度とかデバイスを指定します。これは後で変更可能ですし、複数のソリューションを用意することもできます。
今回はZedBoardを想定してZynq7020を設定。速度はデフォルト。
設定後。あ、デバイス間違えてるw
設定完了後の画面。ここにテストベンチとか追加して行きます。
使い方はほぼEclipseのままです。
上のメニューとかボタン。
緑の再生ボタンがHDL生成。その左がC/C++シミュレーション。この二つをよく使います。
Debug、Synthesis、Analysisはパースペクティブの切り替え。Debugは普通のCデバッガです。Analysisがハードウェアのデータの流れを解析するツールになります。
ここからソースを記述していきます。順番として
・テストベンチ作成。リファレンスとなるデータの読み書きを行うプログラムを書きます。
・ハードウェアになる対象の関数を作成。
・対象の関数を最適化。しなくても良いかも。
・ディレクティブ(指示子?)追加。I/Oの種類とかパイプラインとか。
てな感じで行きます。
Xilinx大丈夫? [FPGA]
ものすごく久々。たまには書きますか。いきなりネガティブですが(笑)
しばらくXilinx使ってます。ISEのProject Navigatorは新規デザインには推奨しないとのことなので、PlanAheadです。Spartan6なのでVivadoは使えません。
えらい初歩的なところで問題起こしてます。
・ISE14.2。Clocking Wizardで作ったモジュールを足すとクリティカルワーニング。曰くウィザードが自分でプロジェクトに足したucfファイルで定義されている信号が見つからないと…知りませんがな、そんなこと。
・同じくISE14.2。MicroBlazeのモジュールでも似た問題が。こちらはncfファイルで信号が見つからないと…だからなんで自分で足す制約にデザインに無い信号名入れるの?
この問題はISE14.3、14.4でも健在。クリティカルでもワーニングなので無視してもインプリは終わります。この制約ファイルは無くても問題ないので、ucfはプロジェクトから削除または無効。ncfは消せないので編集しちゃいました。
・ISE14.3。Clocking Wizardでモジュールを設定した後、再度ウィザードを立ち上げると、設定がデフォルトに。出力を何MHzにしてあっても、100MHzに戻されてます。
・ISE14.4。同じくClocking Wizard。マニュアルでPLLを設定してもDCMを使ってくれちゃう。PLLでしか実装できないパラメータを入れるとPLLを使う。再度ウィザードを立ち上げると設定がAUTOになってる。
Clocking Wizardばかりですが、FPGAで要となるコンポーネントなので、ここに不安があると使う気になりません。クロックだけならPLLマクロを明示的に呼び出せば良いかもしれませんが、この基本機能がこの有様だと、ほかの機能にどれだけバグが含まれてるのかわかったものではありません。
新しいツールのVivadoに力を入れてるのかもしれませんが、7シリーズ以降でないと使えないし、EDKとの連携がやっと2012.4(14.4)で使えるようになったレベルで、まだまだ不安です。(なんか勘違いしてたようです。まだ使えません。)まるまる2種類のデザインツールを提供してることになるので、やたらサイズでかいし…
SystemVerilog使いたいけど、旧デバイスは切り捨て状態。VHDLは古いままVivadoでも新しくなりそうな様子も無し。その辺は外部の合成ツール仕えと言うことでしょうか?高いって。シミュレータもModelSim切っちゃって、やたら遅くて機能不足なisimだけ。Altera版ModelSimがありがたいです。
それにしても、この問題続きは困ったものです。ISE14.1以降にしないとZynq使えないですが、新しいツールがちゃんと動くのか心配しながら使うのは神経が疲れます。
しばらくXilinx使ってます。ISEのProject Navigatorは新規デザインには推奨しないとのことなので、PlanAheadです。Spartan6なのでVivadoは使えません。
えらい初歩的なところで問題起こしてます。
・ISE14.2。Clocking Wizardで作ったモジュールを足すとクリティカルワーニング。曰くウィザードが自分でプロジェクトに足したucfファイルで定義されている信号が見つからないと…知りませんがな、そんなこと。
・同じくISE14.2。MicroBlazeのモジュールでも似た問題が。こちらはncfファイルで信号が見つからないと…だからなんで自分で足す制約にデザインに無い信号名入れるの?
この問題はISE14.3、14.4でも健在。クリティカルでもワーニングなので無視してもインプリは終わります。この制約ファイルは無くても問題ないので、ucfはプロジェクトから削除または無効。ncfは消せないので編集しちゃいました。
・ISE14.3。Clocking Wizardでモジュールを設定した後、再度ウィザードを立ち上げると、設定がデフォルトに。出力を何MHzにしてあっても、100MHzに戻されてます。
・ISE14.4。同じくClocking Wizard。マニュアルでPLLを設定してもDCMを使ってくれちゃう。PLLでしか実装できないパラメータを入れるとPLLを使う。再度ウィザードを立ち上げると設定がAUTOになってる。
Clocking Wizardばかりですが、FPGAで要となるコンポーネントなので、ここに不安があると使う気になりません。クロックだけならPLLマクロを明示的に呼び出せば良いかもしれませんが、この基本機能がこの有様だと、ほかの機能にどれだけバグが含まれてるのかわかったものではありません。
新しいツールのVivadoに力を入れてるのかもしれませんが、7シリーズ以降でないと使えないし、
SystemVerilog使いたいけど、旧デバイスは切り捨て状態。VHDLは古いままVivadoでも新しくなりそうな様子も無し。その辺は外部の合成ツール仕えと言うことでしょうか?高いって。シミュレータもModelSim切っちゃって、やたら遅くて機能不足なisimだけ。Altera版ModelSimがありがたいです。
それにしても、この問題続きは困ったものです。ISE14.1以降にしないとZynq使えないですが、新しいツールがちゃんと動くのか心配しながら使うのは神経が疲れます。