4つのFIFOのクロックドメインは、Read側が read_clk, Write側が write_clkだ。リセットは、Read側が read_reset, Write側が write_reset だ。read_adfifo : AXI4 Master Read のアドレス転送用FIFOで、16深度の分散RAMを使用するFIFOとする。
read_fifo : AX4 Master Read のデータ転送用FIFOで、512深度のBlockRAMを使用するFIFOとする。
write_adfifo : AX4 Master Write のアドレス転送用FIFOで、16深度の分散RAMを使用するFIFOとする。
write_fifo : AX4 Master Write のデータ転送用FIFOで、512深度のBlockRAMを使用するFIFOとする。
read_clk : ユーザー回路 Read 側のクロック
read_reset : ユーザー回路 Read 側のリセット
read_adfifo_wr_ena : read_adfifoへのWrite Enable、1にすると read_adfifo へのWriteする。
read_adfifo_addr : Readアドレスを入力する(32ビット幅)
read_adfifo_arlen : データ転送数-1 を入力する(8ビット幅)
read_adfifo_full : read_adfifo の fullフラグ
read_fifo_rd_ena : read_fifoの Read Enable
read_fifo_read_data : read_data(32ビット幅または64ビット幅)
read_fifo_empty_n : read_fifoの empty フラグ(active low)、1の時にReadデータがある
read_fifo_almost_empty_n : read_fifo の almost emptyフラグ(active low)、後1つ Read すると empty になる
write_clk : ユーザー回路 write 側のクロック
write_reset : ユーザー回路 write 側のリセット
Writeデータ転送wirte_adfifo_wr_ena : write_adfifo へのWrite Enable、1にすると write_adfifo へのWriteする
write_adfifo_addr : Writeアドレスを入力する(32ビット幅)
write_adfifo_arlen : データ転送数-1 を入力する(8ビット幅)
write_adfifo_full : write_adfifo の fullフラグ
アドレス転送はアドレスとデータ転送長をFIFOにWriteするのは、2クロックに1回を想定している。wirte_fifo_wr_ena : write_fifo へのWrite Enable、1にすると write_fifo へのWriteする
write_fifo_wirte_data : write_data(32ビット幅または64ビット幅)
write_fifo_wstrb : byte enable (4ビットまたは、8ビット)
write_fifo_full : write_fifo の fullフラグ
write_fifo_almost_full : write_fifo の almost full フラグ、後1つで full
write_fifo_empty : write_fifo のデータが空になった。クロックはwrite_clkに載せ替え済み。
-----------------------------------------------------------------------------
--
-- AXI Master用 Slave Bus Function Mode (BFM)
-- axi_slave_BFM.vhd
--
-----------------------------------------------------------------------------
-- 2012/02/25 : M_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
-- 2012/07/04 : READ_ONLY_TRANSACTION を追加。Read機能のみでも+1したデータを出力することが出来るように変更した。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector;
end package m_seq_bfm_pack;
package body m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector is
variable mseq16 : std_logic_vector(15 downto 0);
variable xor_result : std_logic;
begin
xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
mseq16 := mseq16in(14 downto 0) & xor_result;
return mseq16;
end M_SEQ16_BFM_F;
end m_seq_bfm_pack;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use IEEE.math_real.all;
library work;
use work.m_seq_bfm_pack.all;
--library unisim;
--use unisim.vcomponents.all;
entity axi_slave_bfm is
generic (
C_M_AXI_ID_WIDTH : integer := 1;
C_M_AXI_ADDR_WIDTH : integer := 32;
C_M_AXI_DATA_WIDTH : integer := 32;
C_M_AXI_AWUSER_WIDTH : integer := 1;
C_M_AXI_ARUSER_WIDTH : integer := 1;
C_M_AXI_WUSER_WIDTH : integer := 1;
C_M_AXI_RUSER_WIDTH : integer := 1;
C_M_AXI_BUSER_WIDTH : integer := 1;
C_M_AXI_TARGET : integer := 0;
C_OFFSET_WIDTH : integer := 10; -- 割り当てるRAMのアドレスのビット幅
C_M_AXI_BURST_LEN : integer := 256;
WRITE_RANDOM_WAIT : integer := 1; -- Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_RANDOM_WAIT : integer := 0; -- Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_ONLY_TRANSACTION : integer := 0 -- Read, Write Transaciton 双方を使用する = 0(RAMにWriteしたものをReadする)、Read Transaciton のみ使用する = 1(データは+1したデータをReadデータとして使用する
);
port(
-- System Signals
ACLK : in std_logic;
ARESETN : in std_logic;
-- Master Interface Write Address Ports
M_AXI_AWID : in std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_AWADDR : in std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_AWLEN : in std_logic_vector(8-1 downto 0);
M_AXI_AWSIZE : in std_logic_vector(3-1 downto 0);
M_AXI_AWBURST : in std_logic_vector(2-1 downto 0);
-- M_AXI_AWLOCK : in std_logic_vector(2-1 downto 0);
M_AXI_AWLOCK : in std_logic_vector(1 downto 0);
M_AXI_AWCACHE : in std_logic_vector(4-1 downto 0);
M_AXI_AWPROT : in std_logic_vector(3-1 downto 0);
M_AXI_AWQOS : in std_logic_vector(4-1 downto 0);
M_AXI_AWUSER : in std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
M_AXI_AWVALID : in std_logic;
M_AXI_AWREADY : out std_logic;
-- Master Interface Write Data Ports
M_AXI_WDATA : in std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_WSTRB : in std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
M_AXI_WLAST : in std_logic;
M_AXI_WUSER : in std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
M_AXI_WVALID : in std_logic;
M_AXI_WREADY : out std_logic;
-- Master Interface Write Response Ports
M_AXI_BID : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_BRESP : out std_logic_vector(2-1 downto 0);
M_AXI_BUSER : out std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
M_AXI_BVALID : out std_logic;
M_AXI_BREADY : in std_logic;
-- Master Interface Read Address Ports
M_AXI_ARID : in std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_ARADDR : in std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_ARLEN : in std_logic_vector(8-1 downto 0);
M_AXI_ARSIZE : in std_logic_vector(3-1 downto 0);
M_AXI_ARBURST : in std_logic_vector(2-1 downto 0);
M_AXI_ARLOCK : in std_logic_vector(2-1 downto 0);
M_AXI_ARCACHE : in std_logic_vector(4-1 downto 0);
M_AXI_ARPROT : in std_logic_vector(3-1 downto 0);
M_AXI_ARQOS : in std_logic_vector(4-1 downto 0);
M_AXI_ARUSER : in std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
M_AXI_ARVALID : in std_logic;
M_AXI_ARREADY : out std_logic;
-- Master Interface Read Data Ports
M_AXI_RID : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_RDATA : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_RRESP : out std_logic_vector(2-1 downto 0);
M_AXI_RLAST : out std_logic;
M_AXI_RUSER : out std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
M_AXI_RVALID : out std_logic;
M_AXI_RREADY : in std_logic
);
end axi_slave_bfm;
architecture implementation of axi_slave_bfm is
constant AxBURST_FIXED : std_logic_vector := "00";
constant AxBURST_INCR : std_logic_vector := "01";
constant AxBURST_WRAP : std_logic_vector := "10";
constant RESP_OKAY : std_logic_vector := "00";
constant RESP_EXOKAY : std_logic_vector := "01";
constant RESP_SLVERR : std_logic_vector := "10";
constant RESP_DECERR : std_logic_vector := "11";
constant DATA_BUS_BYTES : natural := C_M_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant ADD_INC_OFFSET : natural := natural(log(real(DATA_BUS_BYTES), 2.0));
-- RAMの生成
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));
-- for write transaction
type write_transaction_state is (idle_wr, awr_wait, awr_accept, wr_burst);
type write_response_state is (idle_wres, bvalid_assert);
type write_wready_state is (idle_wrdy, wready_assert);
signal wrt_cs : write_transaction_state;
signal wrres : write_response_state;
signal wrwr : write_wready_state;
signal addr_inc_step_wr : integer := 1;
signal awready : std_logic;
signal wr_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal wr_bid : std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
signal wr_bresp : std_logic_vector(1 downto 0);
signal wr_bvalid : std_logic;
signal m_seq16_wr : std_logic_vector(15 downto 0);
signal wready : std_logic;
type wready_state is (idle_wready, assert_wready, deassert_wready);
signal cs_wready : wready_state;
signal cdc_we : std_logic;
-- for read transaction
type read_transaction_state is (idle_rd, arr_wait, arr_accept, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdt_cs : read_transaction_state;
signal rdlast : read_last_state;
signal addr_inc_step_rd : integer := 1;
signal arready : std_logic;
signal rd_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal rd_axi_count : std_logic_vector(7 downto 0);
signal rvalid : std_logic;
signal rlast : std_logic;
signal m_seq16_rd : std_logic_vector(15 downto 0);
type rvalid_state is (idle_rvalid, assert_rvalid, deassert_rvalid);
signal cs_rvalid : rvalid_state;
signal read_data_count : std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal reset_1d, reset_2d, reset : std_logic := '1';
begin
-- ARESETN をACLK で同期化
process (ACLK) begin
if ACLK'event and ACLK='1' then
reset_1d <= not ARESETN;
reset_2d <= reset_1d;
end if;
end process;
reset <= reset_2d;
-- AXI4バス Write Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrt_cs <= idle_wr;
awready <= '0';
else
case (wrt_cs) is
when idle_wr =>
if M_AXI_AWVALID='1' then -- M_AXI_AWVALID が1にアサートされた
if rdt_cs=idle_rd then -- Read Transaction が終了している(Writeの方が優先順位が高い)
wrt_cs <= awr_accept;
awready <= '1';
else -- Read Transaction が終了していないのでWait
wrt_cs <= awr_wait;
end if;
end if;
when awr_wait => -- Read Transaction の終了待ち
wrt_cs <= awr_accept;
awready <= '1';
when awr_accept => -- M_AXI_AWREADY をアサート
wrt_cs <= wr_burst;
awready <= '0';
when wr_burst => -- Writeデータの転送
if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wrt_cs <= idle_wr;
end if;
end case;
end if;
end if;
end process;
M_AXI_AWREADY <= awready;
-- m_seq_wr、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr <= (0 => '1', others => '0');
else
if WRITE_RANDOM_WAIT=1 then -- Write Transaction 時にランダムなWaitを挿入する
if wrt_cs=wr_burst and M_AXI_WVALID='1' then
m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
end if;
else -- Wait無し
m_seq16_wr <= (others => '0');
end if;
end if;
end if;
end process;
-- wready の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_wready <= idle_wready;
wready <= '0';
else
case (cs_wready) is
when idle_wready =>
if wrt_cs=awr_accept then -- 次はwr_burst
if m_seq16_wr(7)='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
else -- m_seq16_wr(7)='1' then -- wready='0'
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when assert_wready => -- 一度wreadyがアサートされたら、1つのトランザクションが終了するまでwready='1'
if wrt_cs=wr_burst and M_AXI_WLAST='1' and M_AXI_WVALID='1' then -- 終了
cs_wready <= idle_wready;
wready <= '0';
elsif wrt_cs=wr_burst and M_AXI_WVALID='1' then -- 1つのトランザクション終了。
if m_seq16_wr(7)='1' then
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when deassert_wready =>
if m_seq16_wr(7)='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
end if;
end case;
end if;
end if;
end process;
M_AXI_WREADY <= wready;
cdc_we <= '1' when wrt_cs=wr_burst and wready='1' and M_AXI_WVALID='1' else '0';
-- addr_inc_step_wr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_wr <= 1;
else
if wrt_cs=awr_accept then
case (M_AXI_AWSIZE) is
when "000" => -- 8ビット転送
addr_inc_step_wr <= 1;
when "001" => -- 16ビット転送
addr_inc_step_wr <= 2;
when "010" => -- 32ビット転送
addr_inc_step_wr <= 4;
when "011" => -- 64ビット転送
addr_inc_step_wr <= 8;
when "100" => -- 128ビット転送
addr_inc_step_wr <= 16;
when "101" => -- 256ビット転送
addr_inc_step_wr <= 32;
when "110" => -- 512ビット転送
addr_inc_step_wr <= 64;
when others => --"111" => -- 1024ビット転送
addr_inc_step_wr <= 128;
end case;
end if;
end if;
end if;
end process;
-- wr_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_addr <= (others => '0');
else
if wrt_cs=awr_accept then
wr_addr <= M_AXI_AWADDR(C_OFFSET_WIDTH-1 downto 0);
elsif wrt_cs=wr_burst and M_AXI_WVALID='1' and wready='1' then -- アドレスを進める
wr_addr <= wr_addr + addr_inc_step_wr;
end if;
end if;
end if;
end process;
-- wr_bid の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bid <= "0";
else
if wrt_cs=awr_accept then
wr_bid <= M_AXI_AWID;
end if;
end if;
end if;
end process;
M_AXI_BID <= wr_bid;
-- wr_bresp の処理
-- M_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bresp <= (others => '0');
else
if wrt_cs=awr_accept then
if M_AXI_AWBURST=AxBURST_INCR then -- バーストタイプがアドレス・インクリメントタイプ
wr_bresp <= RESP_OKAY; -- Write Transaction は成功
else
wr_bresp <= RESP_SLVERR; -- エラー
end if;
end if;
end if;
end if;
end process;
M_AXI_BRESP <= wr_bresp;
-- wr_bvalid の処理
-- Write Transaction State Machineには含まない。axi_master のシミュレーションを見ると1クロックで終了しているので、長い間、Master側の都合でWaitしていることは考えない。
-- 次のWrite転送まで遅延しているようであれば、Write Transaction State Machine に入れてブロックすることも考える必要がある。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bvalid <= '0';
else
if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wr_bvalid <= '1';
elsif wr_bvalid='1' and M_AXI_BREADY='1' then -- wr_bvalid が1でMaster側のReadyも1ならばWrite resonse channel の転送も終了
wr_bvalid <= '0';
end if;
end if;
end if;
end process;
M_AXI_BVALID <= wr_bvalid;
M_AXI_BUSER <= (others => '0');
-- AXI4バス Read Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdt_cs <= idle_rd;
arready <= '0';
else
case (rdt_cs) is
when idle_rd =>
if M_AXI_ARVALID='1' then -- Read Transaction 要求
if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
rdt_cs <= arr_accept;
arready <= '1';
else -- Write Transaction が終了していないのでWait
rdt_cs <= arr_wait;
end if;
end if;
when arr_wait => -- Write Transaction の終了待ち
if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
rdt_cs <= arr_accept;
arready <= '1';
end if;
when arr_accept => -- M_AXI_ARREADY をアサート
rdt_cs <= rd_burst;
arready <= '0';
when rd_burst => -- Readデータの転送
if rd_axi_count=0 and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了
rdt_cs <= idle_rd;
end if;
end case;
end if;
end if;
end process;
M_AXI_ARREADY <= arready;
-- m_seq_rd、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_rd <= (others => '1'); -- Writeとシードを変更する
else
if READ_RANDOM_WAIT=1 then -- Read Transaciton のデータ転送でランダムなWaitを挿入する場合
if rdt_cs=rd_burst and M_AXI_RREADY='1' then
m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
end if;
else -- Wati無し
m_seq16_rd <= (others => '0');
end if;
end if;
end if;
end process;
-- rvalid の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_rvalid <= idle_rvalid;
rvalid <= '0';
else
case (cs_rvalid) is
when idle_rvalid =>
if rdt_cs=arr_accept then -- 次はrd_burst
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
else -- m_seq16_rd(7)='1' then -- rvalid='0'
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when assert_rvalid => -- 一度rvalidがアサートされたら、1つのトランザクションが終了するまでrvalid='1'
if rdt_cs=rd_burst and rlast='1' and M_AXI_RREADY='1' then -- 終了
cs_rvalid <= idle_rvalid;
rvalid <= '0';
elsif rdt_cs=rd_burst and M_AXI_RREADY='1' then -- 1つのトランザクション終了。
if m_seq16_rd(7)='1' then
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when deassert_rvalid =>
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
end if;
end case;
end if;
end if;
end process;
M_AXI_RVALID <= rvalid;
-- addr_inc_step_rd の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_rd <= 1;
else
if rdt_cs=arr_accept then
case (M_AXI_ARSIZE) is
when "000" => -- 8ビット転送
addr_inc_step_rd <= 1;
when "001" => -- 16ビット転送
addr_inc_step_rd <= 2;
when "010" => -- 32ビット転送
addr_inc_step_rd <= 4;
when "011" => -- 64ビット転送
addr_inc_step_rd <= 8;
when "100" => -- 128ビット転送
addr_inc_step_rd <= 16;
when "101" => -- 256ビット転送
addr_inc_step_rd <= 32;
when "110" => -- 512ビット転送
addr_inc_step_rd <= 64;
when others => -- "111" => -- 1024ビット転送
addr_inc_step_rd <= 128;
end case;
end if;
end if;
end if;
end process;
-- rd_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_addr <= (others => '0');
else
if rdt_cs=arr_accept then
rd_addr <= M_AXI_ARADDR(C_OFFSET_WIDTH-1 downto 0);
elsif rdt_cs=rd_burst and M_AXI_RREADY='1' and rvalid='1' then
rd_addr <= rd_addr + addr_inc_step_rd;
end if;
end if;
end if;
end process;
-- rd_axi_count の処理(AXIバス側のデータカウント)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_axi_count <= (others => '0');
else
if rdt_cs=arr_accept then -- rd_axi_count のロード
rd_axi_count <= M_AXI_ARLEN;
elsif rdt_cs=rd_burst and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction が1つ終了
rd_axi_count <= rd_axi_count - 1;
end if;
end if;
end if;
end process;
-- rdlast State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdlast <= idle_rlast;
rlast <= '0';
else
case (rdlast) is
when idle_rlast =>
if rd_axi_count=1 and rvalid='1' and M_AXI_RREADY='1' then -- バーストする場合
rdlast <= rlast_assert;
rlast <= '1';
elsif rdt_cs=arr_accept and M_AXI_ARLEN=0 then -- 転送数が1の場合
rdlast <= rlast_assert;
rlast <= '1';
end if;
when rlast_assert =>
if rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
rdlast <= idle_rlast;
rlast <= '0';
end if;
end case;
end if;
end if;
end process;
M_AXI_RLAST <= rlast;
-- M_AXI_RID, M_AXI_RUSER の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
M_AXI_RID <= (others => '0');
else
if rdt_cs=arr_accept then
M_AXI_RID <= M_AXI_ARID;
end if;
end if;
end if;
end process;
M_AXI_RUSER <= (others => '0');
-- M_AXI_RRESP は、M_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
M_AXI_RRESP <= (others => '0');
else
if rdt_cs=arr_accept then
if M_AXI_ARBURST=AxBURST_INCR then
M_AXI_RRESP <= RESP_OKAY;
else
M_AXI_RRESP <= RESP_SLVERR;
end if;
end if;
end if;
end if;
end process;
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_M_AXI_DATA_WIDTH/8-1 loop
if M_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= M_AXI_WDATA(i*8+7 downto i*8);
end if;
end loop;
end if;
end if;
end process;
-- Read Transaciton のみの場合のReadデータ(Transction 毎に+1)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
read_data_count <= (others => '0');
else
if rdt_cs=rd_burst and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction が1つ終了
read_data_count <= read_data_count + 1;
end if;
end if;
end if;
end process;
M_AXI_RDATA <= ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))) when READ_ONLY_TRANSACTION=0 else read_data_count;
end implementation;
// Read Write Test
initial begin
USER_dataout = 0;
USER_address = 0;
USER_size = 0;
USER_req_din = 0;
USER_req_write = 0;
@(posedge ARESETN)
#1;
@(posedge ACLK);
#1;
USER_address = 32'h12340000; // read request
USER_size = 32'd800;
USER_req_din = 1'b0;
USER_req_write = 1'b1;
@(posedge ACLK);
#1;
USER_address = 32'h56780000; // write request
USER_dataout = 32'h12345678;
USER_size = 32'd1;
USER_req_din = 1'b1;
USER_req_write = 1'b1;
@(posedge ACLK);
#1;
USER_address = 32'h89AB0000; // write request
USER_dataout = 32'h11223344;
USER_size = 32'd2;
USER_req_din = 1'b1;
USER_req_write = 1'b1;
@(posedge ACLK);
#1;
USER_dataout = 32'h22334455;
@(posedge ACLK);
#1;
USER_req_din = 1'b0;
USER_req_write = 1'b0;
end
1.最初の5つのWriteは初期化
2.画像データのアドレス(0x19107000)
3.ラプラシアン・フィルタ用の画像データのアドレス(0x192DC000)
4.ap_startのWrite
3.2つのデータのvld
1.ap_doneが 1 にならない。
2.ラプラシアン・フィルタのWriteデータが全て 0 になっている。
// lap_filter_axim.c
// AXI4 Master のVivado HLS出力ハードウェア・バージョン
// RGBをYに変換後にラプラシアンフィルタを掛ける。
// ピクセルのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 2013/10/15
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/kernel.h>
#include "lap_fil_axim_uty.h"
#define LAP_FILTER_AXIM_HW_ADDRESS 0x49000000 // ラプラシアン・フィルタのAXI4 Masterハードウェアのアドレス
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
#define BUFSIZE 1024
#define MEASURE_COUNT 5000
int conv_rgb2y(int rgb);
int chkhex(char *str);
volatile unsigned *setup_io(off_t mapped_addr, unsigned int *buf_addr);
int main()
{
FILE *fd;
unsigned int bitmap_dc_reg_addr;
unsigned int read_num;
volatile unsigned *bm_disp_cnt_reg;
unsigned int fb_addr, next_frame_addr;
int return_val;
struct timeval start_time, end_time;
unsigned int rmmap_cnt=0, wmmap_cnt=0;
unsigned int lap_fil_hw, *lap_fil_hw_addr;
char buf[BUFSIZE], *token;
unsigned int val;
unsigned int bitmap_buf;
gettimeofday(&start_time, NULL); // プログラム起動時の時刻を記録
// fb_start_addr.txt の内容をパイプに入れる
memset(buf, '\0', sizeof(buf)); // buf すべてに\0 を入れる
// fb_start_addr.txt を開く
fd = popen("cat /Apps/fb_start_addr.txt", "r");
if (fd != NULL){
read_num = fread(buf, sizeof(unsigned char), BUFSIZE, fd);
if (read_num > 0){
sscanf(buf, "%x\n", &fb_addr);
}
}
pclose(fd);
// ラプラシアンフィルタの結果を入れておくフレーム・バッファ
next_frame_addr = ((fb_addr + (ALL_PIXEL_VALUE*4)) & (~(int)(PAGE_SIZE-1))) + PAGE_SIZE;
// Vivado HLS で作製したラプラシアン・フィルタIPのアドレスを取得
lap_fil_hw_addr = setup_io((off_t)LAP_FILTER_AXIM_HW_ADDRESS, &lap_fil_hw);
lap_fil_initialize(lap_fil_hw_addr); // ラプラシアン・フィルタIPの初期化とap_start
// ラプラシアン・フィルタAXI4 Master IPスタート
return_val = laplacian_fil_hw(lap_fil_hw_addr, fb_addr, next_frame_addr);
printf("return Value = %d\n", return_val);
munmap((unsigned int *)lap_fil_hw_addr, BLOCK_SIZE);
free((unsigned int *)lap_fil_hw);
// bitmap-disp-cntrler-axi-master のアドレスを取得
memset(buf, '\0', sizeof(buf)); // buf すべてに\0 を入れる
// ls /sys/devices/axi.0 の内容をパイプに入れる
fd = popen("ls /sys/devices/axi.0", "r");
if (fd != NULL){
read_num = fread(buf, sizeof(unsigned char), BUFSIZE, fd);
if (read_num > 0){
token = buf;
if ((token=strtok(token, ".\n")) != NULL){
do {
if (chkhex(token)){ // 16進数
sscanf(token, "%x", &val);
} else {
if (strcmp(token, "bitmap-disp-cntrler-axi-master") == 0)
bitmap_dc_reg_addr = val;
}
}while((token=strtok(NULL, ".\n")) != NULL);
}
}
}
pclose(fd);
// ラプラシアンフィルタの掛かった画像のスタートアドレスを bitmap-disp-cntrler-axi-master にセット
bm_disp_cnt_reg = setup_io((off_t)bitmap_dc_reg_addr, &bitmap_buf);
*bm_disp_cnt_reg = next_frame_addr;
munmap((unsigned int *)bm_disp_cnt_reg, BLOCK_SIZE);
free((unsigned int *)bitmap_buf);
gettimeofday(&end_time, NULL);
printf("rmmap_cnt = %d\n", rmmap_cnt);
printf("wmmap_cnt = %d\n", wmmap_cnt);
if (end_time.tv_usec < start_time.tv_usec) {
printf("total time = %d.%6.6d sec\n", end_time.tv_sec - start_time.tv_sec - 1, 1000000 + end_time.tv_usec - start_time.tv_usec);
}
else {
printf("total time = %d.%6.6d sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
}
return(0);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
//
// Set up a memory regions to access GPIO
//
volatile unsigned *setup_io(off_t mapped_addr, unsigned int *buf_addr)
// void setup_io()
{
int mem_fd;
char *gpio_mem, *gpio_map;
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
printf("mapped_addr = %x\n", mapped_addr);
exit (-1);
}
/* mmap GPIO */
// Allocate MAP block
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
*buf_addr = gpio_mem; // mallocしたアドレスをコピー
// Make sure pointer is on 4K boundary
if ((unsigned long)gpio_mem % PAGE_SIZE)
gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
// Now map it
gpio_map = (unsigned char *)mmap(
(caddr_t)gpio_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
mapped_addr
);
if ((long)gpio_map < 0) {
printf("mmap error %d\n", (int)gpio_map);
printf("mapped_addr = %x\n", mapped_addr);
exit (-1);
}
close(mem_fd); // /dev/mem のクローズ
// Always use volatile pointer!
// gpio = (volatile unsigned *)gpio_map;
return((volatile unsigned *)gpio_map);
} // setup_io
// 文字列が16進数かを調べる
int chkhex(char *str){
while (*str != '\0'){
if (!isxdigit(*str))
return 0;
str++;
}
return 1;
}
// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2013.2
// Copyright (C) 2013 Xilinx Inc. All rights reserved.
//
// ==============================================================
// LiteS
// 0x00 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read)
// bit 7 - auto_restart (Read/Write)
// others - reserved
// 0x04 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x10 : Control signal of cam_addr
// bit 0 - cam_addr_ap_vld (Read/Write/COH)
// bit 1 - cam_addr_ap_ack (Read)
// others - reserved
// 0x14 : Data signal of cam_addr
// bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x18 : Control signal of lap_addr
// bit 0 - lap_addr_ap_vld (Read/Write/SC)
// others - reserved
// 0x1c : Data signal of lap_addr
// bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x20 : Data signal of ap_return
// bit 31~0 - ap_return[31:0] (Read)
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
#define XLAP_FILTER_AXIM_LITES_ADDR_AP_CTRL 0x00
#define XLAP_FILTER_AXIM_LITES_ADDR_GIE 0x04
#define XLAP_FILTER_AXIM_LITES_ADDR_IER 0x08
#define XLAP_FILTER_AXIM_LITES_ADDR_ISR 0x0c
#define XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_CTRL 0x10
#define XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_DATA 0x14
#define XLAP_FILTER_AXIM_LITES_BITS_CAM_ADDR_DATA 32
#define XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_CTRL 0x18
#define XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_DATA 0x1c
#define XLAP_FILTER_AXIM_LITES_BITS_LAP_ADDR_DATA 32
#define XLAP_FILTER_AXIM_LITES_ADDR_AP_RETURN 0x20
#define XLAP_FILTER_AXIM_LITES_BITS_AP_RETURN 32
/*
* lap_fil_axim_uty.h
*
* Created on: 2013/10/15
* Author: Masaaki
*/
#ifndef LAP_FIL_AXIM_UTY_H_
#define LAP_FIL_AXIM_UTY_H_
void lap_fil_initialize(unsigned int *lap_fil_hw_addr);
int laplacian_fil_hw(unsigned int *lap_fil_hw_addr, unsigned int *cam_fb, unsigned int *lap_fb);
#endif /* LAP_FIL_AXIM_UTY_H_ */
/* * lap_fil_axim_uty.c * * Created on: 2013/10/15 * Author: Masaaki */
#include "xlap_filter_axim_hw.h"
#define AP_START_BIT_POS 1 // ap_start のビット位置 bit0
#define AP_DONE_BIT_POS 2 // ap_done のビット位置 bit1
#define AP_AUTO_RESTART_BIT_POS 0x80 // auto_restart のビット位置 bit7
#define VLD_BIT_POS 1
void lap_fil_initialize(unsigned int *lap_fil_hw_addr)
{
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_GIE) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_IER) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_CTRL) = 0;
}
// ラプラシアン・フィルタ・スタート
int laplacian_fil_hw(unsigned int *lap_fil_hw_addr, unsigned int cam_fb, unsigned int lap_fb)
{
int ap_status, ap_done;
int ap_return;
int cam_fb_read, lap_fb_read;
int cam_addr_vld, lap_addr_vld;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_DATA) = cam_fb;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_DATA) = lap_fb;
cam_fb_read = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_DATA);
lap_fb_read = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_DATA);
// ap_start enable
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_CTRL) = AP_START_BIT_POS;
// vld enable
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_CTRL) = VLD_BIT_POS;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_CTRL) = VLD_BIT_POS;
// wait ap_done
do{
ap_status = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_CTRL);
ap_done = ap_status & AP_DONE_BIT_POS;
cam_addr_vld = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_CTRL);
lap_addr_vld = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_CTRL);
}while(!ap_done);
// ap_return read
ap_return = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_RETURN);
//printf("ap_return = %d\n", ap_return);
return(ap_return);
}
Vivado HLSでラプラシアン・フィルタ関数をaxi masterモジュールにする1
Vivado HLSでラプラシアン・フィルタ関数をaxi masterモジュールにする2
// laplacian_filter.c
// lap_filter_axim()
#include <stdio.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int lap_filter_axim(int *cam_addr, int *lap_addr, volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE ap_hs port=cam_addr
#pragma HLS INTERFACE ap_vld port=lap_addr
#pragma HLS RESOURCE variable=cam_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS RESOURCE variable=lap_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS RESOURCE variable=return core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS INTERFACE ap_bus port=cam_fb depth=480000
#pragma HLS INTERFACE ap_bus port=lap_fb depth=480000
#pragma HLS RESOURCE variable=cam_fb core=AXI4M
#pragma HLS RESOURCE variable=lap_fb core=AXI4M
unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
unsigned int offset;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (x == 1){ // ラインの最初でラインの画素を読み出す
if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
for (a=0; a<3; a++){ // 3ライン分
offset = *cam_addr/sizeof(int);
memcpy(line_buf[a], (const int*)(cam_fb+offset+(a*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[a][b] = conv_rgb2y(line_buf[a][b]); // カラーから白黒へ
}
}
}
} else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
offset = *cam_addr/sizeof(int);
memcpy(line_buf[(y+1)%3], (const int*)(cam_fb+offset+((y+1)*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]); // カラーから白黒へ
}
}
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
offset = *lap_addr/sizeof(int);
memcpy((int *)(lap_fb+offset+(y*HORIZONTAL_PIXEL_WIDTH)), (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
return(1);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
// return(abs(-x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2)); // 元の実装
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// Read Write Test
initial begin
USER_dataout = 0;
USER_address = 0;
USER_size = 0;
USER_req_din = 0;
USER_req_write = 0;
@(posedge ARESETN)
#1;
@(posedge ACLK);
#1;
USER_address = 32'h12340000; // read request
USER_size = 32'd800;
USER_req_din = 1'b0;
USER_req_write = 1'b1;
@(posedge ACLK);
#1;
USER_req_din = 1'b0;
USER_req_write = 1'b0;
end
Vivado HLSでラプラシアン・フィルタ関数をaxi masterモジュールにする1
Vivado HLSでラプラシアン・フィルタ関数をaxi masterモジュールにする2(Vivado HLSの出力したIPのトップファイルのポート構成はここに書いてあります)
Vivado HLSで作ったラプラシアン・フィルタAXI4 Master IPを使う1
Vivado HLSで作ったラプラシアン・フィルタAXI4 Master IPを使う2
Vivado HLSで作ったラプラシアン・フィルタAXI4 Master IPを使う3
1.フレーム・バッファから1ラインRead
2.Readしたピクセルデータを使ってラプラシアン・フィルタを掛けてラインバッファに格納する
3.ラプラシアン・フィルタの値が入ったラインバッファを異なるフレーム・バッファにWrite
template<int D,int U,int TI,int TD>
struct ap_axis{
ap_int<D> data;
ap_uint<D/8> keep;
ap_uint<D/8> strb;
ap_uint<U> user;
ap_uint<1> last;
ap_uint<TI> id;
ap_uint<TD> dest;
};
と書いたが、”Zynq-7000 All Programmable SoC Seminar 2013”では、AWCACHE、ARCACHEどちらも3、AWCACHE, ARCACHE = 3'b011 が推奨という話だったので、実際にやってみた。実験してみたのは、現在使用しているLinuxを起動してるハードウェアだ。以前のハードウェアをISE14.6に変換して ChipScope を入れようとしたのだが、どうしてもエラーになって入らなかった。うまく入ったのが、このハードウェアだけだったのだ。、char_write_axi_master IP、つまりAXIバスのWrite マスタを追加した時には、AWCACHE = 3、つまりBufferableにすると、BRESPに”10”、SLVERR (Slave error) が帰ってきた。
・「ザイリンクスUltraScale™ 真の次世代アーキテクチャ」
・Vivado® HLS (高位合成ツール)とZynq®-7000 All Programmable SoC全てをCで設計するテクニック
・Zynq-7000 All Programmable SoC搭載のARM CPUの活用 ~複雑なデザインの構築を可能にする性能 向上テクニック~
・Zynq-7000 All Programmable SoCユーザロジックから見たProcessing System活用テクニック
・IPIF(これってスレーブしか出来ませんよね?)を使う
・AR37425をテンプレートにして自作する
・Vivado HLSで作る
//------------------------Address Info-------------------
// 0x00 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read)
// bit 7 - auto_restart (Read/Write)
// others - reserved
// 0x04 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x10 : Control signal of cam_addr
// bit 0 - cam_addr_ap_vld (Read/Write/COH)
// bit 1 - cam_addr_ap_ack (Read)
// others - reserved
// 0x14 : Data signal of cam_addr
// bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x18 : Control signal of lap_addr
// bit 0 - lap_addr_ap_vld (Read/Write/SC)
// others - reserved
// 0x1c : Data signal of lap_addr
// bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x20 : Data signal of ap_return
// bit 31~0 - ap_return[31:0] (Read)
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_DATA) = cam_fb;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_DATA) = lap_fb;
cam_fb_read = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_DATA);
lap_fb_read = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_DATA);
// ap_start enable
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_CTRL) = AP_START_BIT_POS;
// vld enable
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_CTRL) = VLD_BIT_POS;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_CTRL) = VLD_BIT_POS;
@E [SIM-304] Aborting co-simulation: C TB simulation failed.
@E [SIM-320] Generating test vectors failed.
”@E [SIM-4] *** C/RTL co-simulation finished: FAIL ***
//------------------------Address Info-------------------
// 0x00 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read)
// bit 7 - auto_restart (Read/Write)
// others - reserved
// 0x04 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x10 : Control signal of cam_addr
// bit 0 - cam_addr_ap_vld (Read/Write/COH)
// bit 1 - cam_addr_ap_ack (Read)
// others - reserved
// 0x14 : Data signal of cam_addr
// bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x18 : Control signal of lap_addr
// bit 0 - lap_addr_ap_vld (Read/Write/SC)
// others - reserved
// 0x1c : Data signal of lap_addr
// bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x20 : Data signal of ap_return
// bit 31~0 - ap_return[31:0] (Read)
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
// laplacian_filter.c
//
#include <stdio.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int lap_filter_axim(int *cam_addr, int *lap_addr, volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE ap_hs port=cam_addr
#pragma HLS INTERFACE ap_vld port=lap_addr
#pragma HLS RESOURCE variable=cam_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS RESOURCE variable=lap_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS RESOURCE variable=return core=AXI4LiteS metadata="-bus_bundle LiteS"
#pragma HLS INTERFACE ap_bus port=cam_fb depth=480000
#pragma HLS INTERFACE ap_bus port=lap_fb depth=480000
#pragma HLS RESOURCE variable=cam_fb core=AXI4M
#pragma HLS RESOURCE variable=lap_fb core=AXI4M
unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
unsigned int offset;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (x == 1){ // ラインの最初でラインの画素を読み出す
if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
for (a=0; a<3; a++){ // 3ライン分
offset = *cam_addr/sizeof(int);
memcpy(line_buf[a], (const int*)(cam_fb+offset+(a*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[a][b] = conv_rgb2y(line_buf[a][b]); // カラーから白黒へ
}
}
}
} else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
offset = *cam_addr/sizeof(int);
memcpy(line_buf[(y+1)%3], (const int*)(cam_fb+offset+((y+1)*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]); // カラーから白黒へ
}
}
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
offset = *lap_addr/sizeof(int);
memcpy((const int*)(lap_fb+offset+(y*HORIZONTAL_PIXEL_WIDTH)), lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
return(1);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
// return(abs(-x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2)); // 元の実装
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// Testbench of laplacian_filter.c
// M系列データをハードウェアとソフトウェアで、ラプラシアン・フィルタを掛けて、それを比較する
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 40
#define VERTICAL_PIXEL_WIDTH 20
//#define HORIZONTAL_PIXEL_WIDTH 800
//#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y_soft(int rgb);
int lap_filter_axim(int cam_addr, int lap_addr, volatile int *cam_fb, volatile int *lap_fb); // hardware
void laplacian_filter_soft(volatile int *cam_fb, volatile int *lap_fb); // software
int mseq_po[ALL_PIXEL_VALUE];
int hw_lap_po[ALL_PIXEL_VALUE];
int sf_lap_po[ALL_PIXEL_VALUE];
int main()
{
// int *mseq_po, *hw_lap_po, *sf_lap_po;
int *s, *h;
int x, y;
unsigned int lfsr = 1;
int cam_addr, lap_addr;
// ピクセルデータ領域にM系列データを入力
for (y=0, s=mseq_po; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u); /* taps 32 31 29 1 */
// ”線形帰還シフトレジスタ ”参照 : http://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%B8%B0%E9%82%84%E3%82%B7%E3%83%95%E3%83%88%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF
*s = lfsr;
s++;
}
}
cam_addr = (int)mseq_po;
lap_addr = (int)hw_lap_po;
lap_filter_axim(cam_addr, lap_addr, (volatile int *)0, (volatile int *)0); // ハードウェアのラプラシアン・フィルタ
laplacian_filter_soft(mseq_po, sf_lap_po); // ソフトウェアのラプラシアン・フィルタ
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
for (y=0, h=hw_lap_po, s=sf_lap_po; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (*h != *s){
printf("ERROR HW and SW results mismatch x = %d, y = %d, HW = %d, SW = %d\n", x, y, *h, *s);
return(1);
} else {
h++;
s++;
}
}
}
printf("Success HW and SW results match\n");
}
void laplacian_filter_soft(volatile int *cam_fb, volatile int *lap_fb)
{
unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (x == 1){ // ラインの最初でラインの画素を読み出す
if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
for (a=0; a<3; a++){ // 3ライン分
memcpy(&line_buf[a][0], (const int*)&cam_fb[a*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[a][b] = conv_rgb2y(line_buf[a][b]); // カラーから白黒へ
}
}
} else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
memcpy(line_buf[(y+1)%3], (const int*)&cam_fb[(y+1)*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]); // カラーから白黒へ
}
}
}
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
memcpy(&lap_fb[y*(HORIZONTAL_PIXEL_WIDTH)], (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y_soft(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(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);
}
// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2013.2
// Copyright (C) 2013 Xilinx Inc. All rights reserved.
//
// ==============================================================
`timescale 1 ns / 1 ps
module lap_filter_axim_top (
m_axi_cam_fb_AWID,
m_axi_cam_fb_AWADDR,
m_axi_cam_fb_AWLEN,
m_axi_cam_fb_AWSIZE,
m_axi_cam_fb_AWBURST,
m_axi_cam_fb_AWLOCK,
m_axi_cam_fb_AWCACHE,
m_axi_cam_fb_AWPROT,
m_axi_cam_fb_AWQOS,
m_axi_cam_fb_AWUSER,
m_axi_cam_fb_AWVALID,
m_axi_cam_fb_AWREADY,
m_axi_cam_fb_WDATA,
m_axi_cam_fb_WSTRB,
m_axi_cam_fb_WLAST,
m_axi_cam_fb_WUSER,
m_axi_cam_fb_WVALID,
m_axi_cam_fb_WREADY,
m_axi_cam_fb_BID,
m_axi_cam_fb_BRESP,
m_axi_cam_fb_BUSER,
m_axi_cam_fb_BVALID,
m_axi_cam_fb_BREADY,
m_axi_cam_fb_ARID,
m_axi_cam_fb_ARADDR,
m_axi_cam_fb_ARLEN,
m_axi_cam_fb_ARSIZE,
m_axi_cam_fb_ARBURST,
m_axi_cam_fb_ARLOCK,
m_axi_cam_fb_ARCACHE,
m_axi_cam_fb_ARPROT,
m_axi_cam_fb_ARQOS,
m_axi_cam_fb_ARUSER,
m_axi_cam_fb_ARVALID,
m_axi_cam_fb_ARREADY,
m_axi_cam_fb_RID,
m_axi_cam_fb_RDATA,
m_axi_cam_fb_RRESP,
m_axi_cam_fb_RLAST,
m_axi_cam_fb_RUSER,
m_axi_cam_fb_RVALID,
m_axi_cam_fb_RREADY,
m_axi_lap_fb_AWID,
m_axi_lap_fb_AWADDR,
m_axi_lap_fb_AWLEN,
m_axi_lap_fb_AWSIZE,
m_axi_lap_fb_AWBURST,
m_axi_lap_fb_AWLOCK,
m_axi_lap_fb_AWCACHE,
m_axi_lap_fb_AWPROT,
m_axi_lap_fb_AWQOS,
m_axi_lap_fb_AWUSER,
m_axi_lap_fb_AWVALID,
m_axi_lap_fb_AWREADY,
m_axi_lap_fb_WDATA,
m_axi_lap_fb_WSTRB,
m_axi_lap_fb_WLAST,
m_axi_lap_fb_WUSER,
m_axi_lap_fb_WVALID,
m_axi_lap_fb_WREADY,
m_axi_lap_fb_BID,
m_axi_lap_fb_BRESP,
m_axi_lap_fb_BUSER,
m_axi_lap_fb_BVALID,
m_axi_lap_fb_BREADY,
m_axi_lap_fb_ARID,
m_axi_lap_fb_ARADDR,
m_axi_lap_fb_ARLEN,
m_axi_lap_fb_ARSIZE,
m_axi_lap_fb_ARBURST,
m_axi_lap_fb_ARLOCK,
m_axi_lap_fb_ARCACHE,
m_axi_lap_fb_ARPROT,
m_axi_lap_fb_ARQOS,
m_axi_lap_fb_ARUSER,
m_axi_lap_fb_ARVALID,
m_axi_lap_fb_ARREADY,
m_axi_lap_fb_RID,
m_axi_lap_fb_RDATA,
m_axi_lap_fb_RRESP,
m_axi_lap_fb_RLAST,
m_axi_lap_fb_RUSER,
m_axi_lap_fb_RVALID,
m_axi_lap_fb_RREADY,
s_axi_LiteS_AWADDR,
s_axi_LiteS_AWVALID,
s_axi_LiteS_AWREADY,
s_axi_LiteS_WDATA,
s_axi_LiteS_WSTRB,
s_axi_LiteS_WVALID,
s_axi_LiteS_WREADY,
s_axi_LiteS_BRESP,
s_axi_LiteS_BVALID,
s_axi_LiteS_BREADY,
s_axi_LiteS_ARADDR,
s_axi_LiteS_ARVALID,
s_axi_LiteS_ARREADY,
s_axi_LiteS_RDATA,
s_axi_LiteS_RRESP,
s_axi_LiteS_RVALID,
s_axi_LiteS_RREADY,
interrupt,
aresetn,
aclk
);
parameter C_M_AXI_CAM_FB_ID_WIDTH = 1;
parameter C_M_AXI_CAM_FB_ADDR_WIDTH = 32;
parameter C_M_AXI_CAM_FB_DATA_WIDTH = 32;
parameter C_M_AXI_CAM_FB_AWUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_ARUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_WUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_RUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_BUSER_WIDTH = 1;
parameter C_M_AXI_CAM_FB_USER_DATA_WIDTH = 32;
parameter C_M_AXI_CAM_FB_TARGET_ADDR = 32'h00000000;
parameter C_M_AXI_CAM_FB_USER_VALUE = 1'b0;
parameter C_M_AXI_CAM_FB_PROT_VALUE = 3'b010;
parameter C_M_AXI_CAM_FB_CACHE_VALUE = 4'b0000;
parameter C_M_AXI_LAP_FB_ID_WIDTH = 1;
parameter C_M_AXI_LAP_FB_ADDR_WIDTH = 32;
parameter C_M_AXI_LAP_FB_DATA_WIDTH = 32;
parameter C_M_AXI_LAP_FB_AWUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_ARUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_WUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_RUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_BUSER_WIDTH = 1;
parameter C_M_AXI_LAP_FB_USER_DATA_WIDTH = 32;
parameter C_M_AXI_LAP_FB_TARGET_ADDR = 32'h00000000;
parameter C_M_AXI_LAP_FB_USER_VALUE = 1'b0;
parameter C_M_AXI_LAP_FB_PROT_VALUE = 3'b010;
parameter C_M_AXI_LAP_FB_CACHE_VALUE = 4'b0000;
parameter C_S_AXI_LITES_ADDR_WIDTH = 6;
parameter C_S_AXI_LITES_DATA_WIDTH = 32;
parameter RESET_ACTIVE_LOW = 1;
// laplacian_filter.c
//
#include <stdio.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
void laplacian_filter(volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE ap_bus port=cam_fb depth=480000
#pragma HLS INTERFACE ap_bus port=lap_fb depth=480000
#pragma HLS RESOURCE variable=cam_fb core=AXI4M
#pragma HLS RESOURCE variable=lap_fb core=AXI4M
unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (x == 1){ // ラインの最初でラインの画素を読み出す
if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
for (a=0; a<3; a++){ // 3ライン分
memcpy(line_buf[a], (const int*)(cam_fb+a*HORIZONTAL_PIXEL_WIDTH), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[a][b] = conv_rgb2y(line_buf[a][b]); // カラーから白黒へ
}
}
}
} else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
memcpy(line_buf[(y+1)%3], (const int*)(cam_fb+((y+1)*HORIZONTAL_PIXEL_WIDTH)), HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]); // カラーから白黒へ
}
}
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
memcpy((const *)(lap_fb+(y*HORIZONTAL_PIXEL_WIDTH)), lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
// return(abs(-x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2)); // 元の実装
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
// Testbench of laplacian_filter.c
// M系列データをハードウェアとソフトウェアで、ラプラシアン・フィルタを掛けて、それを比較する
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HORIZONTAL_PIXEL_WIDTH 40
#define VERTICAL_PIXEL_WIDTH 20
//#define HORIZONTAL_PIXEL_WIDTH 800
//#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil_soft(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y_soft(int rgb);
int lap_filter_axim(int cam_addr, int lap_addr, volatile int *cam_fb, volatile int *lap_fb); // hardware
void laplacian_filter_soft(volatile int *cam_fb, volatile int *lap_fb); // software
int mseq_po[ALL_PIXEL_VALUE];
int hw_lap_po[ALL_PIXEL_VALUE];
int sf_lap_po[ALL_PIXEL_VALUE];
int main()
{
// int *mseq_po, *hw_lap_po, *sf_lap_po;
int *s, *h;
int x, y;
unsigned int lfsr = 1;
int cam_addr, lap_addr;
// ピクセルデータ領域にM系列データを入力
for (y=0, s=mseq_po; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u); /* taps 32 31 29 1 */
// ”線形帰還シフトレジスタ ”参照 : http://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%B8%B0%E9%82%84%E3%82%B7%E3%83%95%E3%83%88%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF
*s = lfsr;
s++;
}
}
cam_addr = (int)mseq_po;
lap_addr = (int)hw_lap_po;
lap_filter_axim(cam_addr, lap_addr, (volatile int *)0, (volatile int *)0); // ハードウェアのラプラシアン・フィルタ
laplacian_filter_soft(mseq_po, sf_lap_po); // ソフトウェアのラプラシアン・フィルタ
// ハードウェアとソフトウェアのラプラシアン・フィルタの値のチェック
for (y=0, h=hw_lap_po, s=sf_lap_po; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (*h != *s){
printf("ERROR HW and SW results mismatch x = %d, y = %d, HW = %d, SW = %d\n", x, y, *h, *s);
return(1);
} else {
h++;
s++;
}
}
}
printf("Success HW and SW results match\n");
}
void laplacian_filter_soft(volatile int *cam_fb, volatile int *lap_fb)
{
unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int a, b;
int fl, sl, tl;
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (x == 1){ // ラインの最初でラインの画素を読み出す
if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
for (a=0; a<3; a++){ // 3ライン分
memcpy(&line_buf[a][0], (const int*)&cam_fb[a*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[a][b] = conv_rgb2y(line_buf[a][b]); // カラーから白黒へ
}
}
} else { // 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
memcpy(line_buf[(y+1)%3], (const int*)&cam_fb[(y+1)*(HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH*sizeof(int));
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]); // カラーから白黒へ
}
}
}
lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
}
memcpy(&lap_fb[y*(HORIZONTAL_PIXEL_WIDTH)], (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
}
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y_soft(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_soft(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);
}
のコメントを外して実行した時のChipScope の結果を下に示す。ピンクの四角で囲ったのが、上のRead アクセスとなる。//x0y0_read = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y0_DATA);
// lap_filter_hls.c
// RGBをYに変換後にラプラシアンフィルタを掛ける。
// ピクセルのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 2013/09/16
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/kernel.h>
#include "lap_filter_uty.h"
#define LAP_FILTER_HW_ADDRESS 0x48000000 // ラプラシアン・フィルタのハードウェアのアドレス
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
#define BUFSIZE 1024
#define MEASURE_COUNT 5000
int laplacian_fil(unsigned int *lap_fil_hw_addr, int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int chkhex(char *str);
volatile unsigned *setup_io(off_t mapped_addr, unsigned int *buf_addr);
void Xil_DCacheInvalidateLine(unsigned int adr);
void Xil_DCacheFlushLine(unsigned int adr);
int main()
{
FILE *fd;
int xy[3][3];
char buf[BUFSIZE], *token;
unsigned int read_num;
unsigned int bitmap_dc_reg_addr;
volatile unsigned *bm_disp_cnt_reg;
unsigned int fb_addr, next_frame_addr;
unsigned int val;
int lap_fil_val;
int x, y;
int *r_pixel, *w_pixel;
unsigned int r_addr, w_addr;
unsigned int r_addr_page, w_addr_page;
unsigned int r_addr_page_pre=0, w_addr_page_pre=0;
unsigned int r_addr_offset, w_addr_offset;
unsigned int r_buf, w_buf, bitmap_buf;
struct timeval start_time, temp1, temp2, end_time;
unsigned int rmmap_cnt=0, wmmap_cnt=0;
unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
int a, b;
int fl, sl, tl;
unsigned int lap_fil_hw, *lap_fil_hw_addr;
gettimeofday(&start_time, NULL); // プログラム起動時の時刻を記録
// fb_start_addr.txt の内容をパイプに入れる
memset(buf, '\0', sizeof(buf)); // buf すべてに\0 を入れる
// fb_start_addr.txt を開く
fd = popen("cat /Apps/fb_start_addr.txt", "r");
if (fd != NULL){
read_num = fread(buf, sizeof(unsigned char), BUFSIZE, fd);
if (read_num > 0){
sscanf(buf, "%x\n", &fb_addr);
}
}
pclose(fd);
// ラプラシアンフィルタの結果を入れておくフレーム・バッファ
next_frame_addr = ((fb_addr + (ALL_PIXEL_VALUE*4)) & (~(int)(PAGE_SIZE-1))) + PAGE_SIZE;
// Vivado HLS で作製したラプラシアン・フィルタIPのアドレスを取得
lap_fil_hw_addr = setup_io((off_t)LAP_FILTER_HW_ADDRESS, &lap_fil_hw);
lap_fil_initialize(lap_fil_hw_addr); // ラプラシアン・フィルタIPの初期化とap_start
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
for (y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
lap_fil_val = 0;
}else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
lap_fil_val = 0;
}else{
if (y == 1 && x == 1){ // 最初のラインの最初のピクセルでは2ライン分の画素を読み出す
for (a=0; a<2; a++){ // 2ライン分
for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
r_addr = fb_addr+((y+(a-1))*HORIZONTAL_PIXEL_WIDTH+b)*4;
r_addr_page = r_addr & (~(int)(PAGE_SIZE-1));
r_addr_offset = r_addr & ((int)(PAGE_SIZE-1));
if (r_addr_page != r_addr_page_pre){ // 以前のページと違うのでunmmap してページの物理アドレスを取り直す
if (r_addr_page_pre != 0){ // 初めの場合はmmap()していないので、munmap()しない
munmap(r_pixel, BLOCK_SIZE);
free((unsigned int *)r_buf);
}
r_pixel = setup_io((off_t)r_addr_page, &r_buf);
rmmap_cnt++;
r_addr_page_pre = r_addr_page;
}
line_buf[a][b] = *(volatile int *)((unsigned int)r_pixel + r_addr_offset);
line_buf[a][b] = conv_rgb2y(line_buf[a][b]);
}
}
}
if (x == 1) { // ラインの最初なので、2つのピクセルを読み込む
for (b=0; b<2; b++){ // ライン
r_addr = fb_addr+((y+1)*HORIZONTAL_PIXEL_WIDTH+b)*4;
r_addr_page = r_addr & (~(int)(PAGE_SIZE-1));
r_addr_offset = r_addr & ((int)(PAGE_SIZE-1));
if (r_addr_page != r_addr_page_pre){ // 以前のページと違うのでunmmap してページの物理アドレスを取り直す
if (r_addr_page_pre != 0){ // 初めの場合はmmap()していないので、munmap()しない
munmap(r_pixel, BLOCK_SIZE);
free((unsigned int *)r_buf);
}
r_pixel = setup_io((off_t)r_addr_page, &r_buf);
rmmap_cnt++;
r_addr_page_pre = r_addr_page;
}
line_buf[(y+1)%3][b] = *(volatile int *)((unsigned int)r_pixel + r_addr_offset);
// (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]);
}
}
// 1つのピクセルを読み込みながらラプラシアン・フィルタを実行する
r_addr = fb_addr+((y+1)*HORIZONTAL_PIXEL_WIDTH+(x+1))*4; // ラプラシアン・フィルタに必要な最後のピクセルを読み込む
r_addr_page = r_addr & (~(int)(PAGE_SIZE-1));
r_addr_offset = r_addr & ((int)(PAGE_SIZE-1));
if (r_addr_page != r_addr_page_pre){ // 以前のページと違うのでunmmap してページの物理アドレスを取り直す
if (r_addr_page_pre != 0){ // 初めの場合はmmap()していないので、munmap()しない
munmap(r_pixel, BLOCK_SIZE);
free((unsigned int *)r_buf);
}
r_pixel = setup_io((off_t)r_addr_page, &r_buf);
rmmap_cnt++;
r_addr_page_pre = r_addr_page;
}
line_buf[(y+1)%3][x+1] = *(volatile int *)((unsigned int)r_pixel + r_addr_offset);
// (y+1)%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
line_buf[(y+1)%3][x+1] = conv_rgb2y(line_buf[(y+1)%3][x+1]);
fl = (y-1)%3; // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
sl = y%3; // 2番めのライン
tl = (y+1)%3; // 3番目のライン
lap_fil_val = laplacian_fil(lap_fil_hw_addr, line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
}
w_addr = next_frame_addr+(y*HORIZONTAL_PIXEL_WIDTH + x)*4;
w_addr_page = w_addr & (~(int)(PAGE_SIZE-1));
w_addr_offset = w_addr & ((int)(PAGE_SIZE-1));
if (w_addr_page != w_addr_page_pre){ // 以前のページと違うのでunmmap してページの物理アドレスを取り直す
if (w_addr_page_pre != 0){ // 初めの場合はmmap()していないので、munmap()しない
munmap(w_pixel, BLOCK_SIZE);
free((unsigned int *)w_buf);
}
w_pixel = setup_io((off_t)w_addr_page, &w_buf);
wmmap_cnt++;
w_addr_page_pre = w_addr_page;
}
*(volatile int *)((unsigned int)w_pixel + w_addr_offset) = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
//printf("x = %d y = %d\n", x, y);
}
a++;
}
munmap((unsigned int *)r_addr_page, BLOCK_SIZE);
free((unsigned int *)r_buf);
munmap((unsigned int *)w_addr_page, BLOCK_SIZE);
free((unsigned int *)w_buf);
munmap((unsigned int *)lap_fil_hw_addr, BLOCK_SIZE);
free((unsigned int *)lap_fil_hw);
// bitmap-disp-cntrler-axi-master のアドレスを取得
memset(buf, '\0', sizeof(buf)); // buf すべてに\0 を入れる
// ls /sys/devices/axi.0 の内容をパイプに入れる
fd = popen("ls /sys/devices/axi.0", "r");
if (fd != NULL){
read_num = fread(buf, sizeof(unsigned char), BUFSIZE, fd);
if (read_num > 0){
token = buf;
if ((token=strtok(token, ".\n")) != NULL){
do {
if (chkhex(token)){ // 16進数
sscanf(token, "%x", &val);
} else {
if (strcmp(token, "bitmap-disp-cntrler-axi-master") == 0)
bitmap_dc_reg_addr = val;
}
}while((token=strtok(NULL, ".\n")) != NULL);
}
}
}
pclose(fd);
// ラプラシアンフィルタの掛かった画像のスタートアドレスを bitmap-disp-cntrler-axi-master にセット
bm_disp_cnt_reg = setup_io((off_t)bitmap_dc_reg_addr, &bitmap_buf);
*bm_disp_cnt_reg = next_frame_addr;
munmap((unsigned int *)bm_disp_cnt_reg, BLOCK_SIZE);
free((unsigned int *)bitmap_buf);
gettimeofday(&end_time, NULL);
printf("rmmap_cnt = %d\n", rmmap_cnt);
printf("wmmap_cnt = %d\n", wmmap_cnt);
if (end_time.tv_usec < start_time.tv_usec) {
printf("total time = %d.%d sec\n", end_time.tv_sec - start_time.tv_sec - 1, 1000000 + end_time.tv_usec - start_time.tv_usec);
}
else {
printf("total time = %d.%d sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
}
return(0);
}
// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y = 0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
int r, g, b, y_f;
int y;
b = rgb & 0xff;
g = (rgb>>8) & 0xff;
r = (rgb>>16) & 0xff;
y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
y = y_f >> 8; // 256で割る
return(y);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(unsigned int *lap_fil_hw_addr, int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
//return(abs(-x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2));
return(laplacian_fil_hw(lap_fil_hw_addr, x0y0, x1y0, x2y0, x0y1, x1y1, x2y1, x0y2, x1y2, x2y2));
}
//
// Set up a memory regions to access GPIO
//
volatile unsigned *setup_io(off_t mapped_addr, unsigned int *buf_addr)
// void setup_io()
{
int mem_fd;
char *gpio_mem, *gpio_map;
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
printf("mapped_addr = %x\n", mapped_addr);
exit (-1);
}
/* mmap GPIO */
// Allocate MAP block
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
*buf_addr = gpio_mem; // mallocしたアドレスをコピー
// Make sure pointer is on 4K boundary
if ((unsigned long)gpio_mem % PAGE_SIZE)
gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
// Now map it
gpio_map = (unsigned char *)mmap(
(caddr_t)gpio_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
mapped_addr
);
if ((long)gpio_map < 0) {
printf("mmap error %d\n", (int)gpio_map);
printf("mapped_addr = %x\n", mapped_addr);
exit (-1);
}
close(mem_fd); // /dev/mem のクローズ
// Always use volatile pointer!
// gpio = (volatile unsigned *)gpio_map;
return((volatile unsigned *)gpio_map);
} // setup_io
// 文字列が16進数かを調べる
int chkhex(char *str){
while (*str != '\0'){
if (!isxdigit(*str))
return 0;
str++;
}
return 1;
}
// axi lite slave utility routine of laplacian filter
// 2013/10/07
//
void lap_fil_initialize(unsigned int *lap_fil_hw_addr);
int laplacian_fil_hw(unsigned int *lap_fil_hw_addr, int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
// axi lite slave utility routine of laplacian filter
// 2013/10/07
//
#include "xlaplacian_filter_hw.h"
#define AP_START_BIT_POS 1 // ap_start のビット位置 bit0
#define AP_DONE_BIT_POS 2 // ap_done のビット位置 bit1
void lap_fil_initialize(unsigned int *lap_fil_hw_addr)
{
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_AP_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_GIE) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_IER) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y0_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y0_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y0_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y1_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y1_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y1_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y2_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y2_CTRL) = 0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y2_CTRL) = 0;
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil_hw(unsigned int *lap_fil_hw_addr, int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int ap_status, ap_done;
int ap_return;
int x0y0_read;
// data Write
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y0_DATA) = x0y0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y0_DATA) = x1y0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y0_DATA) = x2y0;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y1_DATA) = x0y1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y1_DATA) = x1y1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y1_DATA) = x2y1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y2_DATA) = x0y2;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y2_DATA) = x1y2;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y2_DATA) = x2y2;
//x0y0_read = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y0_DATA);
// ap_start enable
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_AP_CTRL) = AP_START_BIT_POS;
// vld enable
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y0_CTRL) = 1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y0_CTRL) = 1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y0_CTRL) = 1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y1_CTRL) = 1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y1_CTRL) = 1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y1_CTRL) = 1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y2_CTRL) = 1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y2_CTRL) = 1;
*(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y2_CTRL) = 1;
// wait ap_done
do{
ap_status = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_AP_CTRL);
ap_done = ap_status & AP_DONE_BIT_POS;
}while(!ap_done);
// ap_return read
ap_return = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAPLACIAN_FILTER_BUS_A_ADDR_AP_RETURN);
//printf("ap_return = %d\n", ap_return);
return(abs(ap_return));
}
// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2013.2
// Copyright (C) 2013 Xilinx Inc. All rights reserved.
//
// ==============================================================
// BUS_A
// 0x00 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read)
// bit 7 - auto_restart (Read/Write)
// others - reserved
// 0x04 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x10 : Control signal of x0y0
// bit 0 - x0y0_ap_vld (Read/Write/COH)
// bit 1 - x0y0_ap_ack (Read)
// others - reserved
// 0x14 : Data signal of x0y0
// bit 31~0 - x0y0[31:0] (Read/Write)
// 0x18 : Control signal of x1y0
// bit 0 - x1y0_ap_vld (Read/Write/SC)
// others - reserved
// 0x1c : Data signal of x1y0
// bit 31~0 - x1y0[31:0] (Read/Write)
// 0x20 : Control signal of x2y0
// bit 0 - x2y0_ap_vld (Read/Write/SC)
// others - reserved
// 0x24 : Data signal of x2y0
// bit 31~0 - x2y0[31:0] (Read/Write)
// 0x28 : Control signal of x0y1
// bit 0 - x0y1_ap_vld (Read/Write/SC)
// others - reserved
// 0x2c : Data signal of x0y1
// bit 31~0 - x0y1[31:0] (Read/Write)
// 0x30 : Control signal of x1y1
// bit 0 - x1y1_ap_vld (Read/Write/SC)
// others - reserved
// 0x34 : Data signal of x1y1
// bit 31~0 - x1y1[31:0] (Read/Write)
// 0x38 : Control signal of x2y1
// bit 0 - x2y1_ap_vld (Read/Write/SC)
// others - reserved
// 0x3c : Data signal of x2y1
// bit 31~0 - x2y1[31:0] (Read/Write)
// 0x40 : Control signal of x0y2
// bit 0 - x0y2_ap_vld (Read/Write/SC)
// others - reserved
// 0x44 : Data signal of x0y2
// bit 31~0 - x0y2[31:0] (Read/Write)
// 0x48 : Control signal of x1y2
// bit 0 - x1y2_ap_vld (Read/Write/SC)
// others - reserved
// 0x4c : Data signal of x1y2
// bit 31~0 - x1y2[31:0] (Read/Write)
// 0x50 : Control signal of x2y2
// bit 0 - x2y2_ap_vld (Read/Write/SC)
// others - reserved
// 0x54 : Data signal of x2y2
// bit 31~0 - x2y2[31:0] (Read/Write)
// 0x58 : Data signal of ap_return
// bit 31~0 - ap_return[31:0] (Read)
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
#define XLAPLACIAN_FILTER_BUS_A_ADDR_AP_CTRL 0x00
#define XLAPLACIAN_FILTER_BUS_A_ADDR_GIE 0x04
#define XLAPLACIAN_FILTER_BUS_A_ADDR_IER 0x08
#define XLAPLACIAN_FILTER_BUS_A_ADDR_ISR 0x0c
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y0_CTRL 0x10
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y0_DATA 0x14
#define XLAPLACIAN_FILTER_BUS_A_BITS_X0Y0_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y0_CTRL 0x18
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y0_DATA 0x1c
#define XLAPLACIAN_FILTER_BUS_A_BITS_X1Y0_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y0_CTRL 0x20
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y0_DATA 0x24
#define XLAPLACIAN_FILTER_BUS_A_BITS_X2Y0_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y1_CTRL 0x28
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y1_DATA 0x2c
#define XLAPLACIAN_FILTER_BUS_A_BITS_X0Y1_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y1_CTRL 0x30
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y1_DATA 0x34
#define XLAPLACIAN_FILTER_BUS_A_BITS_X1Y1_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y1_CTRL 0x38
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y1_DATA 0x3c
#define XLAPLACIAN_FILTER_BUS_A_BITS_X2Y1_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y2_CTRL 0x40
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X0Y2_DATA 0x44
#define XLAPLACIAN_FILTER_BUS_A_BITS_X0Y2_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y2_CTRL 0x48
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X1Y2_DATA 0x4c
#define XLAPLACIAN_FILTER_BUS_A_BITS_X1Y2_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y2_CTRL 0x50
#define XLAPLACIAN_FILTER_BUS_A_ADDR_X2Y2_DATA 0x54
#define XLAPLACIAN_FILTER_BUS_A_BITS_X2Y2_DATA 32
#define XLAPLACIAN_FILTER_BUS_A_ADDR_AP_RETURN 0x58
#define XLAPLACIAN_FILTER_BUS_A_BITS_AP_RETURN 32
// ap_start
always @(posedge ACLK) begin
if (~ARESETN)
ap_start <= 1'b0;
else if (w_hs && waddr == ADDR_AP_CTRL && WSTRB[0] && WDATA[0])
ap_start <= 1'b1;
else if (O_ap_ready)
ap_start <= auto_restart; // clear on handshake/auto restart
end
// _x0y0_ap_vld
always @(posedge ACLK) begin
if (~ARESETN)
_x0y0_ap_vld <= 1'b0;
else if (w_hs && waddr == ADDR_X0Y0_CTRL && WSTRB[0] && WDATA[0])
_x0y0_ap_vld <= 1'b1;
else if (I_x0y0_ap_ack)
_x0y0_ap_vld <= 1'b0; // clear on handshake
end
zynq> ./lap_filter_hls.elf
rmmap_cnt = 469
wmmap_cnt = 469
total time = 1.945109 sec
zynq> ./lap_filter_hls.elf
rmmap_cnt = 469
wmmap_cnt = 469
total time = 1.943671 sec
zynq> ./lap_filter_hls.elf
rmmap_cnt = 469
wmmap_cnt = 469
total time = 1.944409 sec
zynq> ./lap_filter_hls.elf
rmmap_cnt = 469
wmmap_cnt = 469
total time = 1.944262 sec
zynq> ./lap_filter_hls.elf
rmmap_cnt = 469
wmmap_cnt = 469
total time = 1.944169 sec
`timescale 1ns / 1ps
module lap_fil_tb;
// Inputs
reg ap_clk = 1'b0;
reg ap_rst;
reg ap_start;
reg x0y0_ap_vld;
reg x1y0_ap_vld;
reg x2y0_ap_vld;
reg x0y1_ap_vld;
reg x1y1_ap_vld;
reg x2y1_ap_vld;
reg x0y2_ap_vld;
reg x1y2_ap_vld;
reg x2y2_ap_vld;
reg [31:0] x0y0;
reg [31:0] x1y0;
reg [31:0] x2y0;
reg [31:0] x0y1;
reg [31:0] x1y1;
reg [31:0] x2y1;
reg [31:0] x0y2;
reg [31:0] x1y2;
reg [31:0] x2y2;
// Outputs
wire ap_done;
wire ap_idle;
wire ap_ready;
wire x0y0_ap_ack;
wire [31:0] ap_return;
parameter CLK_PERIOD = 10;
parameter real CLK_DUTY_CYCLE = 0.5;
parameter CLK_OFFSET = 0;
parameter START_STATE = 1'b0;
initial begin
#CLK_OFFSET;
forever begin
ap_clk = START_STATE;
#(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) ap_clk = ~START_STATE;
#(CLK_PERIOD*CLK_DUTY_CYCLE);
end
end
// Instantiate the Unit Under Test (UUT)
laplacian_filter uut (
.ap_clk(ap_clk),
.ap_rst(ap_rst),
.ap_start(ap_start),
.ap_done(ap_done),
.ap_idle(ap_idle),
.ap_ready(ap_ready),
.x0y0_ap_vld(x0y0_ap_vld),
.x1y0_ap_vld(x1y0_ap_vld),
.x2y0_ap_vld(x2y0_ap_vld),
.x0y1_ap_vld(x0y1_ap_vld),
.x1y1_ap_vld(x1y1_ap_vld),
.x2y1_ap_vld(x2y1_ap_vld),
.x0y2_ap_vld(x0y2_ap_vld),
.x1y2_ap_vld(x1y2_ap_vld),
.x2y2_ap_vld(x2y2_ap_vld),
.x0y0(x0y0),
.x0y0_ap_ack(x0y0_ap_ack),
.x1y0(x1y0),
.x2y0(x2y0),
.x0y1(x0y1),
.x1y1(x1y1),
.x2y1(x2y1),
.x0y2(x0y2),
.x1y2(x1y2),
.x2y2(x2y2),
.ap_return(ap_return)
);
initial begin
// Initialize Inputs
ap_rst = 1;
ap_start = 0;
x0y0_ap_vld = 0;
x1y0_ap_vld = 0;
x2y0_ap_vld = 0;
x0y1_ap_vld = 0;
x1y1_ap_vld = 0;
x2y1_ap_vld = 0;
x0y2_ap_vld = 0;
x1y2_ap_vld = 0;
x2y2_ap_vld = 0;
x0y0 = 0;
x1y0 = 0;
x2y0 = 0;
x0y1 = 0;
x1y1 = 0;
x2y1 = 0;
x0y2 = 0;
x1y2 = 0;
x2y2 = 0;
// Wait 100 ns for global reset to finish
#10;
// Add stimulus here
@(posedge ap_clk); #1;
ap_rst = 0;
@(posedge ap_clk); #1;
ap_start = 1;
@(posedge ap_clk); #1;
@(posedge ap_clk); #1;
@(posedge ap_clk); #1;
x0y0 = 1;
x1y0 = 1;
x2y0 = 1;
x0y1 = 1;
x1y1 = 2;
x2y1 = 1;
x0y2 = 1;
x1y2 = 1;
x2y2 = 1;
x0y0_ap_vld = 1;
x1y0_ap_vld = 1;
x2y0_ap_vld = 1;
x0y1_ap_vld = 1;
x1y1_ap_vld = 1;
x2y1_ap_vld = 1;
x0y2_ap_vld = 1;
x1y2_ap_vld = 1;
x2y2_ap_vld = 1;
@(posedge ap_clk); #1;
x0y0 = 0;
x1y0 = 1;
x2y0 = 1;
x0y1 = 1;
x1y1 = 2;
x2y1 = 1;
x0y2 = 1;
x1y2 = 1;
x2y2 = 0;
@(posedge ap_clk); #1;
x0y0 = 0;
x1y0 = 1;
x2y0 = 0;
x0y1 = 1;
x1y1 = 2;
x2y1 = 1;
x0y2 = 0;
x1y2 = 1;
x2y2 = 0;
@(posedge ap_clk); #1;
@(posedge ap_clk); #1;
@(posedge ap_clk); #1;
@(posedge ap_clk); #1;
@(posedge ap_clk); #1;
@(posedge ap_clk); #1;
@(posedge ap_clk); #1;
$stop;
end
endmodule
// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2013.2
// Copyright (C) 2013 Xilinx Inc. All rights reserved.
//
// ===========================================================
`timescale 1 ns / 1 ps
(* CORE_GENERATION_INFO="laplacian_filter,hls_ip_2013_2,{HLS_INPUT_TYPE=c,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=0,HLS_INPUT_PART=xc7z020clg484-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=pipeline,HLS_SYN_CLOCK=7.320000,HLS_SYN_LAT=2,HLS_SYN_TPT=1,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=491,HLS_SYN_LUT=578}" *)
module laplacian_filter (
ap_clk,
ap_rst,
ap_start,
ap_done,
ap_idle,
ap_ready,
x0y0_ap_vld,
x1y0_ap_vld,
x2y0_ap_vld,
x0y1_ap_vld,
x1y1_ap_vld,
x2y1_ap_vld,
x0y2_ap_vld,
x1y2_ap_vld,
x2y2_ap_vld,
x0y0,
x0y0_ap_ack,
x1y0,
x2y0,
x0y1,
x1y1,
x2y1,
x0y2,
x1y2,
x2y2,
ap_return
);
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | 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 | - | - |