C/C++ベースのFPGA開発をはじめるにあたって,まずはVivado HLSの使い方をFPGAで動作するビットストリームの作り方まで一通り学んでしまいましょう.この章では,とりあえずVivado HLSを使った開発ができるようになるために,ツールを一通り使ってC/C++で書いたコードからFPGAで動作するビットストリームを生成する作業までを一通り体験してみることにします.習うより慣れろ,ですね.
例題
VivaoHLSでは,基本的な制御構文のC/C++コードをHDLモジュールにすることができます.ここでは,簡単なプログラムをハードウェア化してみましょう.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
int bitcount(int a)
{
int i;
int s = 0;
int tmp = a;
for(i = 0; i < 32; i++){
if((tmp & 0x01) == 0x01){
s++;
}
tmp = tmp >> 1;
}
return s;
}
|
Vivado HLSプロジェクトの作成
Vivado HLS上での設計
Vivado HLSでの動作確認
IPコアの生成
生成したモジュールをFPGAプロジェクトで利用する
top.vhdの内容は次の内容で書きかえる.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity top is
Port ( clk : in STD_LOGIC;
a : in STD_LOGIC_VECTOR (3 downto 0);
q : out STD_LOGIC_VECTOR (3 downto 0));
end top;
architecture Behavioral of top is
component test_0
port (
ap_clk : in std_logic;
ap_rst : in std_logic;
ap_start : in std_logic;
ap_done : out std_logic;
ap_idle : out std_logic;
ap_ready : out std_logic;
a : in std_logic_vector(31 downto 0);
ap_return : out std_logic_vector(31 downto 0)
);
end component;
attribute mark_debug : string; -- 動作確認のためにmark_debugアトリビュートを使う
signal q_i : std_logic_vector(31 downto 0);
begin
q <= q_i(3 downto 0);
U : test_0
port map(
ap_clk => clk,
ap_rst => '0',
ap_start => '1',
ap_done => ap_done,
ap_idle => ap_idle,
ap_ready => ap_ready,
a(31 downto 4) => (others => '0'),
a(3 downto 0) => a,
ap_return => q_i
);
end Behavioral;
|
実機で動作を確認
実機での動作を確認できます.DIPスイッチをON/OFFしたときにONの個数がカウントできていることがわかります.が,残念ながらよくみてみると,DIPスイッチを2つONにした状態,つまり1bit目のLEDのみが点灯すべきケースで,0bit目のLEDが若干点灯していることがわかります.これはバグなので原因を探してみましょう.
ここでは,ILAを使って,実機で動作を確認してみます.まず,topモジュールを次のように書き変えて,いくつかの信号をILAで観測できるようにしましょう.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity top is
Port ( clk : in STD_LOGIC;
a : in STD_LOGIC_VECTOR (3 downto 0);
q : out STD_LOGIC_VECTOR (3 downto 0));
end top;
architecture Behavioral of top is
component test_0
port (
ap_clk : in std_logic;
ap_rst : in std_logic;
ap_start : in std_logic;
ap_done : out std_logic;
ap_idle : out std_logic;
ap_ready : out std_logic;
a : in std_logic_vector(31 downto 0);
ap_return : out std_logic_vector(31 downto 0)
);
end component;
attribute mark_debug : string; -- 動作確認のためにmark_debugアトリビュートを使う
signal q_i : std_logic_vector(31 downto 0);
attribute mark_debug of q_i : signal is "true"; -- mark_debugに指定
-- ステータス信号を引出しILAで観測するために追加
signal ap_done : std_logic;
signal ap_idle : std_logic;
signal ap_ready : std_logic;
attribute mark_debug of ap_done : signal is "true";
attribute mark_debug of ap_idle : signal is "true";
attribute mark_debug of ap_ready : signal is "true";
-- ステータス信号を引出しILAで観測するために追加,ここまで
begin
q <= q_i(3 downto 0);
U : test_0
port map(
ap_clk => clk,
ap_rst => '0',
ap_start => '1',
ap_done => ap_done,
ap_idle => ap_idle,
ap_ready => ap_ready,
a(31 downto 4) => (others => '0'),
a(3 downto 0) => a,
ap_return => q_i
);
end Behavioral;
|
Vivado HLSのシミュレーション結果を詳細に確認する
実はILAを挿入するまでもなく,Vivado HLSのC/RTL協調シミュレーションの結果を注意深く確認することで,今回のバグは防ぐことができます.試してみましょう.
再度実機での動作確認
バグ修正を反映して,もう一度,実機で動作を確認してみましょう.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity top is
Port ( clk : in STD_LOGIC;
a : in STD_LOGIC_VECTOR (3 downto 0);
q : out STD_LOGIC_VECTOR (3 downto 0));
end top;
architecture Behavioral of top is
component test_0
port (
ap_clk : in std_logic;
ap_rst : in std_logic;
ap_start : in std_logic;
ap_done : out std_logic;
ap_idle : out std_logic;
ap_ready : out std_logic;
a : in std_logic_vector(31 downto 0);
ap_return : out std_logic_vector(31 downto 0)
);
end component;
attribute mark_debug : string;
signal q_i : std_logic_vector(31 downto 0);
attribute mark_debug of q_i : signal is "true";
signal ap_done : std_logic;
signal ap_idle : std_logic;
signal ap_ready : std_logic;
attribute mark_debug of ap_done : signal is "true";
attribute mark_debug of ap_idle : signal is "true";
attribute mark_debug of ap_ready : signal is "true";
begin
-- バグ修正のために追加
process(clk)
begin
if rising_edge(clk) then
if ap_done = '1' then
q <= q_i(3 downto 0);
end if;
end if;
end process;
-- バグ修正のために追加,ここまで
U : test_0
port map(
ap_clk => clk,
ap_rst => '0',
ap_start => '1',
ap_done => ap_done,
ap_idle => ap_idle,
ap_ready => ap_ready,
a(31 downto 4) => (others => '0'),
a(3 downto 0) => a,
ap_return => q_i
);
end Behavioral;
|