本文的思路框架:
①本文采用支持3x3算子模块和5x5算子模块的生成,用于后一级别的算法输入
②本例程中采用的FPGA设计技巧,可用于借鉴,一是generate if参数定义;二是调用xilinx和altera的sync fifo和async fifo原语实现不同平台同步fifo和异步fifo的功能,省去ip核的调用,简化代码移植
在图像处理过程中,需要对图像进行滤波操作,在进行滤波操作通常使用算子模板,即扫描窗模板,一般有 3x3、5x5 等模板形式
3x3算子模板
5x5算子模板
使用 FIFO 来缓存图像的行数据,如果取 3x3 的模板,那么至少需要两个深度大于图像行数据的长度的 FIFO,通过首尾相连的形式来缓存两行数据,等第三行数据到来之时,同时输出三行数据。
同理如果是5x5的模板,需要四个深度大于行数据长度的FIFO,通过收尾相连的形式来缓存四行数据,等第五行数据到来之时,同时输出五行数据。其余类推即可。
3x3模板设计及部分代码分析
代码实现功能分析:
1、generate if参数定义,未选择部分,eda软件会自动优化掉,不会造成逻辑资源浪费。
2、调用xilinx和altera的sync fifo和async fifo原语实现不同平台同步fifo和异步fifo的功能,省去ip核的调用,简化代码移植
①xilinx sync fifo和async fifo的原语调用
generate
if(ASYNC_CLK == 1)
begin : ASYNC_FIFO
xpm_fifo_async #(
.CDC_SYNC_STAGES(3), // DECIMAL
.DOUT_RESET_VALUE("0"), // String
.ECC_MODE("no_ecc"), // String
.FIFO_MEMORY_TYPE(FIFO_MEMORY_TYPE), // String
.FIFO_READ_LATENCY(FIFO_READ_LATENCY), // DECIMAL
.FIFO_WRITE_DEPTH(FIFO_DEPTH), // DECIMAL
.FULL_RESET_VALUE(1), // DECIMAL
.PROG_EMPTY_THRESH(5), // DECIMAL
.PROG_FULL_THRESH(PROG_FULL_THRESH), // DECIMAL
.RD_DATA_COUNT_WIDTH(COUNT_WIDTH), // DECIMAL
.READ_DATA_WIDTH(WRITE_DATA_WIDTH), // DECIMAL
.READ_MODE(FIFO_READ_MODE), // String
.RELATED_CLOCKS(0), // DECIMAL
.SIM_ASSERT_CHK(0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
.USE_ADV_FEATURES("1707"), // String
.WAKEUP_TIME(0), // DECIMAL
.WRITE_DATA_WIDTH(WRITE_DATA_WIDTH), // DECIMAL
.WR_DATA_COUNT_WIDTH(COUNT_WIDTH) // DECIMAL
)
xpm_fifo_inst (
.almost_empty (), //unused
.almost_full (), //unused
.data_valid (),
.dbiterr (),
.dout (o_rd_data ),
.empty (o_rd_empty ),
.full (o_wr_full ),
.overflow (),
.prog_empty (o_rd_arempty ),
.prog_full (o_wr_awfull ),
.rd_data_count (o_rd_cnt ),
.rd_rst_busy (),
.sbiterr (),
.underflow (),
.wr_ack (), //unused
.wr_data_count (o_wr_cnt ),
.wr_rst_busy (),
.din (i_wr_data ),
.injectdbiterr (1'b0),
.injectsbiterr (1'b0),
.rd_clk (i_rd_clk ),
.rd_en (i_rd_en ),
.rst (i_wr_rst || i_rd_rst ),
.sleep (1'b0),
.wr_clk (i_wr_clk ),
.wr_en (i_wr_en )
);
end
// End of xpm_fifo_async_inst instantiation
else begin : SYNC_FIFO
xpm_fifo_sync #(
.DOUT_RESET_VALUE("0"), // String
.ECC_MODE("no_ecc"), // String
.FIFO_MEMORY_TYPE(FIFO_MEMORY_TYPE), // String
.FIFO_READ_LATENCY(FIFO_READ_LATENCY), // DECIMAL
.FIFO_WRITE_DEPTH(FIFO_DEPTH), // DECIMAL
.FULL_RESET_VALUE(1), // DECIMAL
.PROG_EMPTY_THRESH(5), // DECIMAL
.PROG_FULL_THRESH(PROG_FULL_THRESH), // DECIMAL
.RD_DATA_COUNT_WIDTH(COUNT_WIDTH), // DECIMAL
.READ_DATA_WIDTH(WRITE_DATA_WIDTH), // DECIMAL
.READ_MODE(FIFO_READ_MODE), // String
.SIM_ASSERT_CHK(0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
.USE_ADV_FEATURES("1707"), // String
.WAKEUP_TIME(0), // DECIMAL
.WRITE_DATA_WIDTH(WRITE_DATA_WIDTH), // DECIMAL
.WR_DATA_COUNT_WIDTH(COUNT_WIDTH) // DECIMAL
)
xpm_fifo_inst (
.almost_empty (), //unused
.almost_full (), //unused
.data_valid (),
.dbiterr (),
.dout (o_rd_data ),
.empty (o_rd_empty ),
.full (o_wr_full ),
.overflow (),
.prog_empty (o_rd_arempty ),
.prog_full (o_wr_awfull ),
.rd_data_count (o_rd_cnt ),
.rd_rst_busy (),
.sbiterr (),
.underflow (),
.wr_ack (), //unused
.wr_data_count (o_wr_cnt ),
.wr_rst_busy (),
.din (i_wr_data ),
.injectdbiterr (1'b0),
.injectsbiterr (1'b0),
.rd_en (i_rd_en ),
.rst (i_wr_rst ),
.sleep (1'b0),
.wr_clk (i_wr_clk ),
.wr_en (i_wr_en )
);
end
endgenerate
②altera sync fifo和async fifo的原语调用
generate
if(ASYNC_CLK == 1)
begin : ASYNC_FIFO
dcfifo dcfifo_component (
.rdclk (i_rd_clk ),
.wrclk (i_wr_clk ),
.wrreq (i_wr_en ),
.data (i_wr_data ),
.rdreq (i_rd_en ),
.wrempty (o_rd_empty ),
.wrfull (o_wr_full ),
.q (o_rd_data ),
.rdempty (o_rd_arempty ),
.rdfull (o_wr_awfull ),
.wrusedw (o_wr_cnt ),
.rdusedw (o_rd_cnt ),
.aclr ( )
);
defparam
dcfifo_component.intended_device_family = DEVICE,
dcfifo_component.lpm_numwords = FIFO_DEPTH,
dcfifo_component.lpm_showahead = FIFO_READ_MODE,
dcfifo_component.lpm_type = "dcfifo",
dcfifo_component.lpm_width = DATA_WIDTH,
dcfifo_component.lpm_widthu = ADDR_WIDTH,
dcfifo_component.overflow_checking = "ON",
dcfifo_component.rdsync_delaypipe = 3,
dcfifo_component.underflow_checking = "ON",
dcfifo_component.use_eab = "ON",
dcfifo_component.wrsync_delaypipe = 3;
end
// End of xpm_fifo_async_inst instantiation
else begin : SYNC_FIFO
scfifo scfifo_component(
.clock (i_wr_clk ),
.sclr (i_wr_rst ),
.wrreq (i_wr_en ),
.data (i_wr_data ),
.rdreq (i_rd_en ),
.usedw (o_wr_cnt ),
.empty (o_rd_empty ),
.full (o_wr_full ),
.q (o_rd_data ),
.almost_empty (o_rd_arempty ),
.almost_full (o_wr_awfull ),
.aclr ( )
);
defparam
scfifo_component.add_ram_output_register = "OFF",
scfifo_component.almost_empty_value = 2,
scfifo_component.almost_full_value = PROG_FULL_THRESH,
scfifo_component.intended_device_family = DEVICE,
scfifo_component.lpm_numwords = FIFO_DEPTH,
scfifo_component.lpm_showahead = FIFO_READ_MODE,
scfifo_component.lpm_type = "scfifo",
scfifo_component.lpm_width = DATA_WIDTH,
scfifo_component.lpm_widthu = ADDR_WIDTH,
scfifo_component.overflow_checking = "ON",
scfifo_component.underflow_checking = "ON",
scfifo_component.use_eab = "ON";
end
endgenerate
③xilinx和altera平台fifo选择
generate
if(DEVICE_CHOODE == "xilinx")
begin : XILINX
xilinx_fifo #(
.DATA_WIDTH (DATA_WIDTH ),
.ASYNC_CLK (ASYNC_CLK ),
.ADDR_WIDTH (ADDR_WIDTH ),
.READ_MODE (READ_MODE )//0:STA fifo 1:FWFT
)xilinx_fifo_init(
.i_wr_clk (i_wr_clk ),
.i_wr_rst (i_wr_rst ),
.i_wr_en (i_wr_en ),
.i_wr_data (i_wr_data ),
.o_wr_cnt (o_wr_cnt ),
.o_wr_full (o_wr_full ),
.o_wr_awfull (o_wr_awfull ),
.i_rd_clk (i_rd_clk ),
.i_rd_rst (i_rd_rst ),
.i_rd_en (i_rd_en ),
.o_rd_data (o_rd_data ),
.o_rd_cnt (o_rd_cnt ),
.o_rd_empty (o_rd_empty ),
.o_rd_arempty (o_rd_arempty )
);
end
else begin : ALTERA
altera_fifo #(
.DATA_WIDTH (DATA_WIDTH ),
.ASYNC_CLK (ASYNC_CLK ),
.ADDR_WIDTH (ADDR_WIDTH ),
.READ_MODE (READ_MODE )//0:STA fifo 1:FWFT
)altera_fifo_init(
.i_wr_clk (i_wr_clk ),
.i_wr_rst (i_wr_rst ),
.i_wr_en (i_wr_en ),
.i_wr_data (i_wr_data ),
.o_wr_cnt (o_wr_cnt ),
.o_wr_full (o_wr_full ),
.o_wr_awfull (o_wr_awfull ),
.i_rd_clk (i_rd_clk ),
.i_rd_rst (i_rd_rst ),
.i_rd_en (i_rd_en ),
.o_rd_data (o_rd_data ),
.o_rd_cnt (o_rd_cnt ),
.o_rd_empty (o_rd_empty ),
.o_rd_arempty (o_rd_arempty )
);
end
endgenerate