ほとんど C のコードと同じだが、Java のコードに変更した laplacian_filter.java を下に示す。
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
public class laplacian_filter{
public int lap_filter(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2){
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
}
これを Make ファイルを修正して make した。Makefile の内の関係ある部分を下に示す。
SYNTHESIJER ?= ../../bin
SOURCES = laplacian_filter.java
VHDL_SOURCES = $(SOURCES:.java=.vhd)
VERILOG_SOURCES = $(SOURCES:.java=.v)
all: $(SOURCES)
java -cp $(SYNTHESIJER) synthesijer.Main --verilog --vhdl $(SOURCES)
実行後に、laplacian_filter.vhd と laplacian_filter.v ファイルができた。
VHDLのテストベンチ (sim.vhd) を作製して、laplacian_filter.vhd をテストした。
GHDL + GTKWave では面倒なので、ModelSim AE 10.1e を使用した。
図 1 にシミュレーション結果を示す。
図 1 laplacian_filter.vhd のシミュレーション結果1 - 1
プロトコルを説明する。
lap_filter_req を 1 クロック間 1 にアサートした次のクロックで、lap_filter_busy が 1 にアサートされて計算中を示す。
lap_filter_busy が 0 にディアサートされた時が計算が終了した時で、この時には、lap_filter_return にラプラシアンフィルタの値が確定されている。
lap_filter_busy が 1 にアサートされた時から 0 にディアサートされるまでの幅は 240 ns だった。クロックは100MHz, 10 ns なので、ラプラシアンフィルタの計算に 24 クロックかかっている。
図 2 を見ると、unary_expr_0010 ~ binary_expr_0018 まで 1 クロックごとに 演算しているのがわかる。
図 2 laplacian_filter.vhd のシミュレーション結果1 - 2
lap_filter_req の間隔を狭めると (for i in 0 to 10 loop)、正しい値が出力できなくなる。その様子を図 3 に示す。
図 3 laplacian_filter.vhd のシミュレーション結果2
図 1 と図 2 のシミュレーション結果の sim.vhd を下に示す。
-- sim.vhd
-- Testbench for laplacian_filter.vhd
-- 2014/12/27 by marsee
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity sim is
end sim;
architecture testbench of sim is
component laplacian_filter
port (
clk : in std_logic;
reset : in std_logic;
lap_filter_x0y0 : in signed(32-1 downto 0);
lap_filter_x1y0 : in signed(32-1 downto 0);
lap_filter_x2y0 : in signed(32-1 downto 0);
lap_filter_x0y1 : in signed(32-1 downto 0);
lap_filter_x1y1 : in signed(32-1 downto 0);
lap_filter_x2y1 : in signed(32-1 downto 0);
lap_filter_x0y2 : in signed(32-1 downto 0);
lap_filter_x1y2 : in signed(32-1 downto 0);
lap_filter_x2y2 : in signed(32-1 downto 0);
lap_filter_req : in std_logic;
lap_filter_busy : out std_logic;
lap_filter_return : out signed(32-1 downto 0)
);
end component;
constant clock_period : time := 10 ns;
constant delay : time := 1 ns;
signal clk : std_logic := '0';
signal reset : std_logic;
signal lap_filter_x0y0 : signed(32-1 downto 0);
signal lap_filter_x1y0 : signed(32-1 downto 0);
signal lap_filter_x2y0 : signed(32-1 downto 0);
signal lap_filter_x0y1 : signed(32-1 downto 0);
signal lap_filter_x1y1 : signed(32-1 downto 0);
signal lap_filter_x2y1 : signed(32-1 downto 0);
signal lap_filter_x0y2 : signed(32-1 downto 0);
signal lap_filter_x1y2 : signed(32-1 downto 0);
signal lap_filter_x2y2 : signed(32-1 downto 0);
signal lap_filter_req : std_logic;
signal lap_filter_busy : std_logic;
signal lap_filter_return : signed(32-1 downto 0);
begin
clk <= not clk after clock_period/2; -- clk = 100MHz, 10 ns
uut : laplacian_filter port map (
clk => clk,
reset => reset,
lap_filter_x0y0 => lap_filter_x0y0,
lap_filter_x1y0 => lap_filter_x1y0,
lap_filter_x2y0 => lap_filter_x2y0,
lap_filter_x0y1 => lap_filter_x0y1,
lap_filter_x1y1 => lap_filter_x1y1,
lap_filter_x2y1 => lap_filter_x2y1,
lap_filter_x0y2 => lap_filter_x0y2,
lap_filter_x1y2 => lap_filter_x1y2,
lap_filter_x2y2 => lap_filter_x2y2,
lap_filter_req => lap_filter_req,
lap_filter_busy => lap_filter_busy,
lap_filter_return => lap_filter_return
);
stimulus : process begin
reset <= '1';
lap_filter_x0y0 <= to_signed(0, 32);
lap_filter_x1y0 <= to_signed(0, 32);
lap_filter_x2y0 <= to_signed(0, 32);
lap_filter_x0y1 <= to_signed(0, 32);
lap_filter_x1y1 <= to_signed(0, 32);
lap_filter_x2y1 <= to_signed(0, 32);
lap_filter_x0y2 <= to_signed(0, 32);
lap_filter_x1y2 <= to_signed(0, 32);
lap_filter_x2y2 <= to_signed(0, 32);
lap_filter_req <= '0';
wait for 100 ns;
reset <= '0';
wait for 50 ns;
lap_filter_x0y0 <= to_signed(127, 32);
lap_filter_x1y0 <= to_signed(127, 32);
lap_filter_x2y0 <= to_signed(127, 32);
lap_filter_x0y1 <= to_signed(127, 32);
lap_filter_x1y1 <= to_signed(127, 32);
lap_filter_x2y1 <= to_signed(127, 32);
lap_filter_x0y2 <= to_signed(0, 32);
lap_filter_x1y2 <= to_signed(0, 32);
lap_filter_x2y2 <= to_signed(0, 32);
wait until clk'event and clk='1';
wait for delay;
lap_filter_req <= '1';
wait until clk'event and clk='1';
wait for delay;
lap_filter_req <= '0';
for i in 0 to 22 loop
wait until clk'event and clk='1';
wait for delay;
end loop;
lap_filter_x0y0 <= to_signed(127, 32);
lap_filter_x1y0 <= to_signed(127, 32);
lap_filter_x2y0 <= to_signed(127, 32);
lap_filter_x0y1 <= to_signed(127, 32);
lap_filter_x1y1 <= to_signed(81, 32);
lap_filter_x2y1 <= to_signed(127, 32);
lap_filter_x0y2 <= to_signed(0, 32);
lap_filter_x1y2 <= to_signed(0, 32);
lap_filter_x2y2 <= to_signed(0, 32);
wait until clk'event and clk='1';
wait for delay;
lap_filter_req <= '1';
wait until clk'event and clk='1';
wait for delay;
lap_filter_req <= '0';
wait for 1 us;
assert (false) report "Simulation End!" severity failure;
end process;
end testbench;