XILINX FIR IP 详解、Verilog 源码、Vivado 工程

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_46621272/article/details/125292610

XILINX FIR IP 详解、Verilog 源码、Vivado 工程


文章目录


前言

FIR 是个比较复杂的 IP ,不同的设置需要不同的代码去配合。这篇文章详细介绍了这 FIR IP 设置需要注意的地方。
本文中介绍了五个实验,最基础的应用实验,FIR +FIFO实验,多通道多套系数配置实验,Reload Config 实验等,全面介绍了 FIR 的各种应用。所有实验提供 Vivado工程,Verilog代码下载,还有较为详细的文字图片介绍。


一、FIR IP 详解(Vivado 2017.4 环境 FIR Compiler 7.2)

XILINX 官方 FIR 手册: https://docs.xilinx.com/v/u/en-US/pg149-fir-compiler
本文只介绍一些常用到的功能设置,和需要注意的地方。一些没介绍到的功能和细节请仔细阅读手册。
在这里插入图片描述

  • 01:这部分很多人容易忽略,需要时刻关注这部分,在做一些 Reload/Config/多通道/等应用设置后,要及时查看这部分的变化。

  • 02: FIR 系数,本文的所有例子都是采用 COE File 方式导入 FIR 系数文件,本文的“COE”文件是由 Matlab 下的
    Filter Designer 生成,相关方法和使用请看本文的附件二。

  • 03:多套系数的导入,这个数需要我们填写,还需要根据这个数去合理的人工合并编辑 COE 文件或 Vector 内容。这里需要注意的是我们在合并 COE 文件时,最好选用相同系数的数量及相同的系数对称方式去合并。

    • A:最好选用相同系数的对称方式的COE数据去合并
      系数的对称方式简介:
      奇对称:系数数量是奇数,且左右对称,比如:1,-2,3,-2,1
      偶对称:系数数量是偶数,且左右对称,比如:-1,2,2,-1
      负对称:系数数量是偶数,且左右负对称,比如:1,-2,3,-3,2,-1
      不对称:比如:1,-2,3,4
    • B:最好选用相同系数数量的 COE 系数去合并,在数量不一致且对称方式一样的情况下,可以手工补 0 的方式将 COE 的系数数量调整到一致。
      比如:
      B1:对称系数:0, 1,-2, 3,-2, 1, 0 (前后补 0 ,可以补多个 0)
      B2:不对称系数: 1,-2,3,4,0,0 (后补 0 ,可以补多个 0)
    • C:在系数数量不同,而且系数对称方式不一致时,也能合并。需要将所有的系数都按不对称处理。这种模式下会占用较多的 DSP 资源。
      C1:需要在 FIR Coefficient Options的设置中将 Coefficient Structure 选成 Non-symmetric (不对称方式)
      C2:按不对称系数的后补 0 方式将所有数据的数量调整成一样再合并
      可以参考下本文后面的实验,有具体的例子和代码:
    • FIR 高级应用 - 多通道共用一个 FIR (四个通道共用同一个 FIR I+P 每个通道采用不同的 FIR 系数算法)。
    • FIR 高级应用 FIR Reload、Config 的使用。
    • D:在编辑 COE 文件补 0 时要补全比如 16 位系数,要敲 “0000” 四个零,要敲全。

    • D1:奇对称 5 个系数和奇对称 7 个系数合并
    • 奇对称 5 个系数文件
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0001,
      0002,
      0003,
      0002,
      0001;

    • 奇对称 7 个系数文件
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0005,
      0004,
      0003,
      0002,
      0003,
      0004,
      0005;

    • 奇对称 5 个系数和奇对称 7 个系数合并后
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0000,
      0001,
      0002,
      0003,
      0002,
      0001,
      0000,
      0005,
      0004,
      0003,
      0002,
      0003,
      0004,
      0005;


    • D2: 偶对称 6 个系数,奇对称 5 个系数合并,这只能按不对称补 0 合并
    • 偶对称 6 个系数文件
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0001,
      0002,
      0003,
      0003,
      0002,
      0001;

    • 奇对称 5 个系数文件
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0003,
      0004,
      0005,
      0004,
      0003;

    • 奇对称 5 个系数和 5.coe 偶对称 6 个系数合并后文件,按不对称后补 0
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0001,
      0002,
      0003,
      0003,
      0002,
      0001,
      0003,
      0004,
      0005,
      0004,
      0003,
      0000;

  • 04:Reload 重新加载系数


    • A:重新加载的系数与原系数的数量必须一致,如果不一致可以参考 03 将系数补 0 的方式调整成一样。
    • B:重新加载的系数的对称方式必须一致,如果不一致可以参考 03 将系数的对称方式全部按不对称处理。
    • C:重新加载的系数必须用 Config 去激活才能生效。
    • D:可以参考下本文后面的实验:FIR 高级应用 FIR Reload、Config 的使用
    • E:人工编辑、补 0 Reload 数据,对称数据需要折半后前补 0

    • E1:Reload 奇对称数据编辑,按 9 个长度补 0 折半后就是 5 个系数数据。
    • 奇对称 5 个系数,按对称数据折半后前补 0
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0001,
      0002,
      000a,
      0002,
      0001;
    • 编辑后
      0000
      0000
      0001
      0002
      000a

    • 奇对称 7 个系数,按对称数据折半后前补 0
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0005,
      000b,
      0003,
      0002,
      0003,
      000b,
      0005;
    • 编辑后
      0000
      0005
      000b
      0003
      0002

    • D2:Reload 偶对称数据编辑,按 10 个长度补 0 折半后就是 5 个系数数据。
    • 偶对称 6 个系数,按对称数据折半后前补 0
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0001,
      0002,
      0003,
      0003,
      0002,
      0001;
    • 编辑后
      0000
      0000
      0001
      0002
      0003

    • 偶对称 4 个系数,按对称数据折半后前补 0
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 000a,
      000b,
      000b,
      000a;
    • 编辑后
      0000
      0000
      0000
      000a
      000b

    • E3:Reload 奇偶对称混合数据编辑,按 10 个长度补 0 ,按不对称数据处理。
    • 奇对称 5 个系数,按不对称数据后补 0
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0001,
      0002,
      000a,
      0002,
      0001;
    • 编辑后
      0001
      0002
      000a
      0002
      0001
      0000
      0000
      0000
      0000
      0000

    • 偶对称 6 个系数,按不对称数据后补 0
      Radix = 16;
      Coefficient_Width = 16;
      CoefData = 0001,
      0002,
      0003,
      0003,
      0002,
      0001;
    • 编辑后
      0001
      0002
      0003
      0003
      0002
      0001
      0000
      0000
      0000
      0000
  • 05: Filter Specification 滤波器类型,可以支持以下五种类型

    FIR IP 持 5 种滤波类型
    Single-rate (缺省)
    Interpolating
    Decimating (实验 FIR 高级应用 - AM 调幅波调制解调通过这个选择改变 FIR 输出的采样频率)
    Hilbert transform
    Interpolated
    我们可以选用合适的类型完成我们的设计。其中的 Interpolating 插值,Decimating 抽值能改变 FIR 输出的采样频率。可以参考下实验的代码。在实验里我们就用 Decimating 类型将采样频率降低为原来的 1/16,将采样频率从 1MHz 降低到 62.5KHz。

在这里插入图片描述

  • 06:Channel Sequence 通道序列选择,在我们的实验中均选用 Basic。在 Number of Channels 通道数量为 1 时也只能选用 Basic。
    Basic 的多通道模式,各通道的采样频率必须同步、一致。
    在 Advanced 选项里,各通道的采样频率允许有限制的不一样,但必须是同步的同一时钟源的。这 Advanced 选项的细节请阅读手册吧。
  • 07:Number of Channels 通道数量,这里的多通道是串行的,比如双通道 C0,C1 这俩通道 C0、C1 交错输入交错输出分时使用。
  • 08:Parallel Channel Specification 并行的通道设置,并行通道数量。各通道的采样频率必须同步、一致。
  • 09:输入的采样时钟频率,这是个虚值,并没用这个采样时钟的管脚。这个值的设置要根据整个 FIR 的应用来决定。
  • 10:FIR 实际工作的时钟频率
  • 11:FIR 时钟设置,09,10 这俩时钟的设置需要是相互关联的。这俩值根据不同的应用会有不同的变化。
  • 应用1: 输入的采样时钟频率和 FIR 实际工作的时钟频率设成一样。
    优点:这种 FIR 的应用,FIR 外围设计非常简单。
    缺点:占用 DSP 资源较大。
    使用范围:适用于高速的采样速率的方案,适用于对 DSP 资源消耗不高的应用。
  • 应用2: 输入的采样时钟频率小于 FIR 实际工作的时钟频率。
    由于输入的采样时钟和 FIR 的工作时钟不同,输入的数据流一般要用一个 FIFO 做跨越时钟域的转换。
    优点:这种 FIR 的应用,能极大的降低 DSP 资源的使用。在一些低速应用中能选用高阶滤波算法。比如一万个系数的 FIR 运算。
    缺点:这种 FIR 的应用,FIR 外围设计设计较复杂,一般需要用 FIFO。
    使用范围:适用于低速的采样速率的方案,适用于对 DSP 资源消耗很高的应用。
  • 应用3: 输入的采样时钟频率大于 FIR 实际工作的时钟频率。
    这种应用能实现超高速的 FIR 应用。这种应用消耗资源成倍的增加。和应用2一样这种应用也需要 FIFO ,应用比较复杂。
    优点:实现超高速的 FIR 运算,比如 7 系列 XILINX FPGA 实现。FIR 的工作时钟能到 300MHz,用这种方法能实现 300MHz * N 的高速计算。
    缺点:这种 FIR 的应用占用 DSP 的资源成 N 倍的增长。FIR 外围设计设计较复杂,一般需要用 FIFO。
    使用范围:适用于超高速的采样速率的方案。

在这里插入图片描述

  • 12:FIR 系数的设置需要和 COE 文件保持一致,在我们的实验中这个设置均为 Signed,16 位宽度。

  • 13:Coefficient Structure 系数结构,自动,对称,非对称,负对称系数的选择。在多组系数 Config 应用和 Reload 应用中,需要设置该值。请参考 03,04章节的介绍,请参考实验。

  • 14:输入输出数据设置,按实际应用去设置位宽和精度。
    在这里插入图片描述

  • 15:请阅读手册。在我们的实验中这部分都是按缺省值设置。
    在这里插入图片描述

  • 16:数据通道选择。按实际应用去选择。

  • 17:USER 输入输出设置,在多通道的实验中 USER Output 设置 Chan ID Field

  • 18:在串行多通道中,该选项能支持每个通道选用不同的 FIR 系数设置。在实验中,选用 By Channel

  • 19:Reload Slots ,在 Reload 应用中需要关注此值,这个值在我们使用 Reload 时,会影响 Reload 时的数据堵塞。这东西文字说不清楚,最好看看实验的代码和波形。
    举例:
    Reload Slots = 1,在 Reload 时只能下载一组系数后就堵塞了,下载数据通过 Config 须激活后才能继续下载数据。
    Reload Slots = 3,在 Reload 时能下载三组系数后就才堵塞,激活后才能继续下载数据。

  • 20:按实际应用去选择。在我们的所有实验中 ARESETn 均为使能。

二、实验内容

实验一、FIR 基础应用 - AM 调幅波调制解调(FIR 低通滤波)。

1. AM 调幅波调制模块

在这里插入图片描述

2. am_modulation_dds.v verilog 代码

//am_modulation_dds.v
module	am_modulation_dds
(
	output			m_axis_data_tvalid,
	input			m_axis_data_tready,
	output	[15:0]	m_axis_data_tdata,
	input			rst_n,
	input			clk
);

	wire signed	[7:0]	dds_100khz_tdata_i;		//	100KHz   正弦波	AM 载波
	wire				dds_100khz_tvalid_i;
	wire				dds_100khz_tready_i;

	wire signed	[7:0]	dds_4khz_tdata_i;		//	4khz   正弦波	AM 调制信号
	wire				dds_4khz_tvalid_i;
	wire				dds_4khz_tready_i;

	reg signed	[15:0]	am_tdata_r;
	reg					am_tvalid_r;
	wire				am_tready_i;

	assign	am_tready_i			= m_axis_data_tready;
	assign	dds_100khz_tready_i	= am_tready_i;
	assign	dds_4khz_tready_i	= am_tready_i;

	assign	m_axis_data_tvalid	= am_tvalid_r;
	assign	m_axis_data_tdata	= am_tdata_r;

	always @(posedge clk)	//AM 调制算法实现
	begin
		if(rst_n == 0 )
		begin
			am_tdata_r	<= 0;
			am_tvalid_r	<= 0;
		end
		else if(am_tready_i == 1)
		begin
			am_tdata_r	<= dds_100khz_tdata_i * (dds_4khz_tdata_i/2 + 128);	// 128 是直流分量,式中的除2是为了不使数据超过16位溢出
																			// 这个代码中,载波频率很低,就直接用乘法去写代码了。
																			// 如果载波频率比较高就需要用DSP单元或乘法 IP 去实现。
			am_tvalid_r	<= dds_4khz_tvalid_i & dds_100khz_tvalid_i;
		end
	end

	dds_compiler_1m_100k dds1						// XILINX VIVADO DDS IP1MHz 时钟输入,100KHz正弦波 8 位输出
	(
		.aclk				(clk),					// input wire aclk
		.aresetn			(rst_n),				// input wire aresetn
		.m_axis_data_tvalid	(dds_100khz_tvalid_i),	// output wire m_axis_data_tvalid
		.m_axis_data_tready	(dds_100khz_tready_i),	// input wire m_axis_data_tready
		.m_axis_data_tdata	(dds_100khz_tdata_i)	// output wire [7 : 0] m_axis_data_tdata
	);

	dds_compiler_1m_4k dds2							// XILINX VIVADO DDS IP1MHz 时钟输入,4khz正弦波 8 位输出
	(
		.aclk				(clk),					// input wire aclk
		.aresetn			(rst_n),				// input wire aresetn
		.m_axis_data_tvalid	(dds_4khz_tvalid_i),	// output wire m_axis_data_tvalid
		.m_axis_data_tready	(dds_4khz_tready_i),	// input wire m_axis_data_tready
		.m_axis_data_tdata	(dds_4khz_tdata_i)		// output wire [7 : 0] m_axis_data_tdata
	);

endmodule

3. AM 调幅波解调模块

在这里插入图片描述

4. am_demodulation_fir.v verilog 代码

//am_demodulation_fir.v
module	am_demodulation_fir
(
	input					rst_n,
	input					clk,
	input					s_axis_data_tvalid,
	output					s_axis_data_tready,
	input	signed[15:0]	s_axis_data_tdata,
	output					m_axis_data_tvalid,
	input					m_axis_data_tready,
	output	signed[15:0]	m_axis_data_tdata
);


	reg 		[15:0]	abs_data_r	= 0;
	reg					abs_valid_r	= 0;
	wire				abs_tready_i;

	always @(posedge clk)
	begin
		if(rst_n == 0 )
			abs_valid_r	<= 0;
		else if(abs_tready_i == 1)
			abs_valid_r	<= s_axis_data_tvalid;
	end

	always @(posedge clk)	//取绝对值
	begin
		if(rst_n == 0 )
			abs_data_r	<= 0;
		else if(abs_tready_i == 1 && s_axis_data_tvalid == 1)
		begin
			if(s_axis_data_tdata >= 0)
				abs_data_r	<= s_axis_data_tdata;
			else
				abs_data_r	<= -s_axis_data_tdata;
		end
	end
	
	wire signed	[39:0]	fir_fm_tdata_i;
	wire				fir_fm_tvalid_i;
	wire				fir_fm_tready_i;

	assign	fir_fm_tready_i		= m_axis_data_tready;
	assign	m_axis_data_tdata	= fir_fm_tdata_i >>>19;
	assign	m_axis_data_tvalid	= fir_fm_tvalid_i;
	assign	s_axis_data_tready	= abs_tready_i;

	fir_compiler_lowpass_10k_30k_1m am_fir_u1
	(
		.aresetn			(rst_n),			// input wire aresetn
		.aclk				(clk),				// input wire aclk
		.s_axis_data_tvalid	(abs_valid_r),		// input wire s_axis_data_tvalid
		.s_axis_data_tready	(abs_tready_i),		// output wire s_axis_data_tready
		.s_axis_data_tdata	(abs_data_r),		// input wire [15 : 0] s_axis_data_tdata
		.m_axis_data_tvalid	(fir_fm_tvalid_i),	// output wire m_axis_data_tvalid
		.m_axis_data_tready	(fir_fm_tready_i),	// input wire m_axis_data_tready
		.m_axis_data_tdata	(fir_fm_tdata_i)	// output wire [39 : 0] m_axis_data_tdata
	);
endmodule


5. am_modem_fir_testbench.v verilog 代码

///////////////////////////////////////////////////////////////////////

`timescale 1ns / 100ps

//am_modem_fir_testbench.v
module am_modem_fir_testbench;

reg			rst_n;
reg			clk;


parameter CLK_PERIOD		= 1000;		//1MHz

initial	begin
	rst_n = 0;
	#(20 * CLK_PERIOD)
	rst_n = 1;
	#(3000 * CLK_PERIOD)
	$stop;
end

initial
	clk = 0;
always
begin
	clk = #(CLK_PERIOD/2.0) ~clk;
end

	wire signed	[15:0]	am_mod_tdata;			//调幅波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
	wire				am_mod_tvalid;
	wire				am_mod_tready;

	wire signed	[15:0]	am_demod_tdata;			//经过解调还原的 4KHz 正弦波
	wire				am_demod_tvalid;
	wire				am_demod_tready=1;

	am_modulation_dds	am_u1					//调幅波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调幅信号
	(
		.clk				(clk),				//1MHz
		.rst_n				(rst_n),			//复位
		.m_axis_data_tdata	(am_mod_tdata),		//调幅波数据输出, output wire [16 : 0]
		.m_axis_data_tvalid	(am_mod_tvalid),
		.m_axis_data_tready	(am_mod_tready)
	);

	am_demodulation_fir		am_u2				//调幅波解调模块,将调幅波解调还原调制信号
	(
		.clk				(clk),				//1MHz
		.rst_n				(rst_n),			//复位
		.s_axis_data_tdata	(am_mod_tdata),		//调幅信号输入 intput wire [16 : 0]
		.s_axis_data_tvalid	(am_mod_tvalid),
		.s_axis_data_tready	(am_mod_tready),
		.m_axis_data_tdata	(am_demod_tdata),	//调幅波解调数据输出, output wire [16 : 0]
		.m_axis_data_tvalid	(am_demod_tvalid),
		.m_axis_data_tready	(am_demod_tready)
	);

endmodule

实验二、FIR 基础应用 - FM 调频波调制解调(FIR 低通滤波)。

1. FM 调频波调制模块

在这里插入图片描述

2. fm_modulation_dds.v verilog 代码

//fm_modulation_dds.v
module	fm_modulation_dds
(
	output			m_axis_data_tvalid,
	input			m_axis_data_tready,
	output	[15:0]	m_axis_data_tdata,
	input			rst_n,
	input			clk
);

	parameter			PHASE_COEF = 6554;//100KHz 


	reg signed	[15:0]	phase_cnt_r;

	wire signed	[15:0]	s_axis_phase_tdata_i;
	reg					s_axis_phase_tvalid_r;
	wire				s_axis_phase_tready_i;
	wire signed	[15:0]	phase_step_i;

	wire signed	[7:0]	dds_4khz_tdata_i;			//	4khz   正弦波	FM 调制信号
	wire				dds_4khz_tvalid_i;
	wire				dds_4khz_tready_i;

	wire signed	[15:0]	fm_tdata_i;					//	FM 调频波
	wire				fm_tvalid_i;
	wire				fm_tready_i;

	assign	phase_step_i 			= dds_4khz_tdata_i*16;
	assign	dds_4khz_tready_i		= s_axis_phase_tready_i;
	assign	s_axis_phase_tdata_i	= phase_cnt_r;
	

	always @(posedge clk)
	begin
		if(rst_n == 0 )
			s_axis_phase_tvalid_r	<= 0;
		else if(s_axis_phase_tready_i == 1)
			s_axis_phase_tvalid_r	<= dds_4khz_tvalid_i;
	end

	always @(posedge clk)
	begin
		if(rst_n == 0 )
		begin
			phase_cnt_r	<= 0;
		end
		else if(s_axis_phase_tready_i == 1 && dds_4khz_tvalid_i == 1)
		begin
			phase_cnt_r	<= phase_cnt_r + phase_step_i + PHASE_COEF;
		end
	end	
	
	dds_compiler_1m_4k dds1							// XILINX VIVADO DDS IP100MHz 时钟输入,4khz正弦波 8 位输出
	(
		.aclk				(clk),					// input wire aclk
		.aresetn			(rst_n),				// input wire aresetn
		.m_axis_data_tvalid	(dds_4khz_tvalid_i),	// output wire m_axis_data_tvalid
		.m_axis_data_tready	(dds_4khz_tready_i),	// input wire m_axis_data_tready
		.m_axis_data_tdata	(dds_4khz_tdata_i)		// output wire [7 : 0] m_axis_data_tdata
	);

	
	dds_compiler_phase dds2
	(
		.aclk				(clk),						// input wire aclk
		.aresetn			(rst_n),					// input wire aresetn
		.s_axis_phase_tvalid(s_axis_phase_tvalid_r),	// input wire s_axis_phase_tvalid
		.s_axis_phase_tready(s_axis_phase_tready_i),	// output wire s_axis_phase_tready
		.s_axis_phase_tdata	(s_axis_phase_tdata_i),		// input wire [15 : 0] s_axis_phase_tdata
		.m_axis_data_tvalid	(fm_tvalid_i),				// output wire m_axis_data_tvalid
		.m_axis_data_tready	(fm_tready_i),				// input wire m_axis_data_tready
		.m_axis_data_tdata	(fm_tdata_i)				// output wire [15 : 0] m_axis_data_tdata
	);
	
	assign	fm_tready_i			= m_axis_data_tready;
	assign	m_axis_data_tvalid	= fm_tvalid_i;
	assign	m_axis_data_tdata	= fm_tdata_i;

endmodule

3. FM 调频波解调模块

在这里插入图片描述

4. fm_demodulation_fir.v verilog 代码

//fm_demodulation_fir.v
module	fm_demodulation_fir
(
	input					rst_n,
	input					clk,
	input					s_axis_data_tvalid,
	output					s_axis_data_tready,
	input	signed[15:0]	s_axis_data_tdata,
	output					m_axis_data_tvalid,
	input					m_axis_data_tready,
	output	signed[15:0]	m_axis_data_tdata
);

	reg signed	[15:0]	uf_data_r	= 0;
	reg signed	[15:0]	sv_data_r	= 0;
	reg					uf_valid_r	= 0;
	wire				uf_tready_i;
	
	reg 		[15:0]	abs_data_r	= 0;
	reg					abs_valid_r	= 0;
	wire				abs_tready_i;

////////////////////////////////////////////////////////////////////////////////////
	always @(posedge clk)		
	begin
		if(rst_n == 0 )
			uf_valid_r	<= 0;
		else if(uf_tready_i == 1)
			uf_valid_r	<= s_axis_data_tvalid;
	end
	
	always @(posedge clk)	//微分 dx/dt ,dt =一个时钟周期,dx=当前数据减去上个时钟的数据的差
	begin
		if(rst_n == 0 )
		begin
			uf_data_r	<= 0;
			sv_data_r	<= 0;
		end
		else if(uf_tready_i == 1 && s_axis_data_tvalid == 1)
		begin
			sv_data_r	<= s_axis_data_tdata;				//将当前数据存起来
			uf_data_r	<= s_axis_data_tdata - sv_data_r;	//当前数据 - 上个时钟保存的数据
		end
	end
////////////////////////////////////////////////////////////////////////////////////
	always @(posedge clk)
	begin
		if(rst_n == 0 )
			abs_valid_r	<= 0;
		else if(abs_tready_i == 1)
			abs_valid_r	<= uf_valid_r;
	end
	
	always @(posedge clk)	//绝对值
	begin
		if(rst_n == 0 )
			abs_data_r	<= 0;
		else if(abs_tready_i == 1 && uf_valid_r == 1)
		begin
			if(uf_data_r >= 0)
				abs_data_r	<= uf_data_r;
			else
				abs_data_r	<= -uf_data_r;
		end
	end
////////////////////////////////////////////////////////////////////////////////////
	
	wire signed	[39:0]	fir_fm_tdata_i;
	wire				fir_fm_tvalid_i;
	wire				fir_fm_tready_i;

	assign	fir_fm_tready_i		= m_axis_data_tready;
	assign	m_axis_data_tdata	= fir_fm_tdata_i >>>19;
	assign	m_axis_data_tvalid	= fir_fm_tvalid_i;
	assign	s_axis_data_tready	= abs_tready_i;
	assign	uf_tready_i			= abs_tready_i;

fir_compiler_lowpass_10k_30k_1m fm_fir_u1
(
	.aresetn			(rst_n),			// input wire aresetn
	.aclk				(clk),				// input wire aclk
	.s_axis_data_tvalid	(abs_valid_r),		// input wire s_axis_data_tvalid
	.s_axis_data_tready	(abs_tready_i),		// output wire s_axis_data_tready
	.s_axis_data_tdata	(abs_data_r),		// input wire [15 : 0] s_axis_data_tdata
	.m_axis_data_tvalid	(fir_fm_tvalid_i),	// output wire m_axis_data_tvalid
	.m_axis_data_tready	(fir_fm_tready_i),	// input wire m_axis_data_tready
	.m_axis_data_tdata	(fir_fm_tdata_i)	// output wire [31 : 0] m_axis_data_tdata
);
endmodule

5. fm_modem_fir_testbench.v verilog 代码


///////////////////////////////////////////////////////////////////////

`timescale 1ns / 100ps
//fm_modem_fir_testbench.v
module fm_modem_fir_testbench;

reg			rst_n;
reg			clk;

parameter CLK_PERIOD	= 1000;		//1MHz


initial	begin
	rst_n = 0;
	#(10 * CLK_PERIOD)
	rst_n = 1;
	#(3000 * CLK_PERIOD)
	$stop;
end

initial
	clk = 0;
always
begin
	clk = #(CLK_PERIOD/2.0) ~clk;
end


	wire signed	[15:0]	fm_mod_tdata;			//调频波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
	wire				fm_mod_tvalid;
	wire				fm_mod_tready;

	wire signed	[15:0]	fm_demod_tdata;			//经过解调还原的 4KHz 正弦波
	wire				fm_demod_tvalid;
	wire				fm_demod_tready=1;

	fm_modulation_dds	fm_u1					//调频波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调频信号
	(
		.clk				(clk),				//1MHz
		.rst_n				(rst_n),			//复位
		.m_axis_data_tdata	(fm_mod_tdata),		//调频波数据输出, output wire [16 : 0]
		.m_axis_data_tvalid	(fm_mod_tvalid),
		.m_axis_data_tready	(fm_mod_tready)
	);

	fm_demodulation_fir	fm_u2					//调频波解调模块,将调频波解调还原调制信号
	(
		.clk				(clk),				//1MHz
		.rst_n				(rst_n),			//复位

		.s_axis_data_tdata	(fm_mod_tdata),		//调频信号输入 intput wire [16 : 0]
		.s_axis_data_tvalid	(fm_mod_tvalid),
		.s_axis_data_tready	(fm_mod_tready),

		.m_axis_data_tdata	(fm_demod_tdata),	//调频波解调数据输出, output wire [16 : 0]
		.m_axis_data_tvalid	(fm_demod_tvalid),
		.m_axis_data_tready	(fm_demod_tready)

	);

endmodule

实验三、FIR 中级应用 - AM 调幅波调制解调(FIR + FIFO)

1. AM 调幅波调制模块,请参考实验一

2. AM 调幅波解调模块(FIR 中级应用)

在这里插入图片描述

3. am_fifo_demodulation_fir.v verilog 代码

//am_fifo_demodulation_fir.v
module	am_fifo_demodulation_fir
(
	input					rst_n,
	input					clk,
	input					clk_100mhz,
	input					s_axis_data_tvalid,
	output					s_axis_data_tready,
	input	signed[15:0]	s_axis_data_tdata,
	output					m_axis_data_tvalid,
	input					m_axis_data_tready,
	output	signed[15:0]	m_axis_data_tdata
);


	reg 		[15:0]	abs_data_r	= 0;
	reg					abs_valid_r	= 0;
	wire				abs_tready_i;

	
	always @(posedge clk)
	begin
		if(rst_n == 0 )
			abs_valid_r	<= 0;
		else if(abs_tready_i == 1)
			abs_valid_r	<= s_axis_data_tvalid;
	end

	always @(posedge clk)
	begin
		if(rst_n == 0 )
			abs_data_r	<= 0;
		else if(abs_tready_i == 1 && s_axis_data_tvalid == 1)
		begin
			if(s_axis_data_tdata >= 0)
				abs_data_r	<= s_axis_data_tdata;
			else
				abs_data_r	<= -s_axis_data_tdata;
		end
	end
	

	assign	s_axis_data_tready	= abs_tready_i;


	wire signed	[15:0]	fifo_as_tdata_i;
	wire				fifo_as_tvalid_i;
	wire				fifo_as_tready_i;
	wire				fifo_as_clk_i;

	wire signed	[15:0]	fifo_am_tdata_i;
	wire				fifo_am_tvalid_i;
	wire				fifo_am_tready_i;
	wire				fifo_am_clk_i;

	wire signed	[15:0]	fifo_bs_tdata_i;
	wire				fifo_bs_tvalid_i;
	wire				fifo_bs_tready_i;
	wire				fifo_bs_clk_i;

	wire signed	[15:0]	fifo_bm_tdata_i;
	wire				fifo_bm_tvalid_i;
	wire				fifo_bm_tready_i;
	wire				fifo_bm_clk_i;


	assign	fifo_as_clk_i		= clk;
	assign	fifo_am_clk_i		= clk_100mhz;
	assign	fifo_bs_clk_i		= clk_100mhz;
	assign	fifo_bm_clk_i		= clk;

	assign	fifo_as_tdata_i		= abs_data_r;
	assign	fifo_as_tvalid_i	= abs_valid_r;
	assign	abs_tready_i		= fifo_as_tready_i;
	
	axi_fifo_a16 fifo_ua
	(
		.wr_rst_busy	(),						// output wire wr_rst_busy
		.rd_rst_busy	(),						// output wire rd_rst_busy
		.m_aclk			(fifo_am_clk_i),		// input wire m_aclk
		.s_aclk			(fifo_as_clk_i),		// input wire s_aclk
		.s_aresetn		(rst_n),				// input wire s_aresetn
		.s_axis_tvalid	(fifo_as_tvalid_i),		// input wire s_axis_tvalid
		.s_axis_tready	(fifo_as_tready_i),		// output wire s_axis_tready
		.s_axis_tdata	(fifo_as_tdata_i),		// input wire [15 : 0] s_axis_tdata
		.m_axis_tvalid	(fifo_am_tvalid_i),		// output wire m_axis_tvalid
		.m_axis_tready	(fifo_am_tready_i),		// input wire m_axis_tready
		.m_axis_tdata	(fifo_am_tdata_i)		// output wire [15 : 0] m_axis_tdata
	);

	wire				fir_a_clk_i;
	
	wire signed	[15:0]	fir_as_tdata_i;
	wire				fir_as_tvalid_i;
	wire				fir_as_tready_i;
	wire signed	[39:0]	fir_am_tdata_i;
	wire				fir_am_tvalid_i;
	wire				fir_am_tready_i;


	assign	fir_a_clk_i			= fifo_am_clk_i;
	
	assign	fir_as_tvalid_i		= fifo_am_tvalid_i;
	assign	fir_as_tdata_i		= fifo_am_tdata_i;
	assign	fifo_am_tready_i	= fir_as_tready_i;

	fir_compiler_lowpass_10k_30k_100m	 am_fir_u1
	(
		.aresetn			(rst_n),			// input wire aresetn
		.aclk				(fir_a_clk_i),		// input wire aclk
		.s_axis_data_tvalid	(fir_as_tvalid_i),	// input wire s_axis_data_tvalid
		.s_axis_data_tready	(fir_as_tready_i),	// output wire s_axis_data_tready
		.s_axis_data_tdata	(fir_as_tdata_i),	// input wire [15 : 0] s_axis_data_tdata
		.m_axis_data_tvalid	(fir_am_tvalid_i),	// output wire m_axis_data_tvalid
		.m_axis_data_tready	(fir_am_tready_i),	// input wire m_axis_data_tready
		.m_axis_data_tdata	(fir_am_tdata_i)	// output wire [39 : 0] m_axis_data_tdata
	);


	assign	fifo_bs_tvalid_i	= fir_am_tvalid_i;
	assign	fifo_bs_tdata_i		= fir_am_tdata_i >>>19;
	assign	fir_am_tready_i		= fifo_bs_tready_i;

	axi_fifo_a16 fifo_ub
	(
		.wr_rst_busy	(),						// output wire wr_rst_busy
		.rd_rst_busy	(),						// output wire rd_rst_busy
		.m_aclk			(fifo_bm_clk_i),		// input wire m_aclk
		.s_aclk			(fifo_bs_clk_i),		// input wire s_aclk
		.s_aresetn		(rst_n),				// input wire s_aresetn
		.s_axis_tvalid	(fifo_bs_tvalid_i),		// input wire s_axis_tvalid
		.s_axis_tready	(fifo_bs_tready_i),		// output wire s_axis_tready
		.s_axis_tdata	(fifo_bs_tdata_i),		// input wire [15 : 0] s_axis_tdata
		.m_axis_tvalid	(fifo_bm_tvalid_i),		// output wire m_axis_tvalid
		.m_axis_tready	(fifo_bm_tready_i),		// input wire m_axis_tready
		.m_axis_tdata	(fifo_bm_tdata_i)		// output wire [15 : 0] m_axis_tdata
	);
	
	assign	fifo_bm_tready_i	= m_axis_data_tready;
	assign	m_axis_data_tdata	= fifo_bm_tdata_i;
	assign	m_axis_data_tvalid	= fifo_bm_tvalid_i;
	
endmodule


4. am_fifo_fir_testbench.v verilog 代码

///////////////////////////////////////////////////////////////////////

`timescale 1ns / 100ps
//am_fifo_fir_testbench.v
module am_fifo_fir_testbench;

reg			rst_n;
reg			clk;
reg			clk_100mhz;

parameter CLK_PERIOD		= 1000;		//1MHz
parameter CLK_PERIOD_100MHz	= 10;		//100MHz

initial	begin
	rst_n = 0;
	#(20 * CLK_PERIOD)
	rst_n = 1;
	#(1000 * CLK_PERIOD)
	$stop;
end

initial
	clk = 0;
always
begin
	clk = #(CLK_PERIOD/2.0) ~clk;
end

initial
	clk_100mhz = 0;
always
begin
	clk_100mhz = #(CLK_PERIOD_100MHz/2.0) ~clk_100mhz;
end

	wire signed	[15:0]	am_mod_tdata;			//调幅波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
	wire				am_mod_tvalid;
	wire				am_mod_tready;

	wire signed	[15:0]	am_demod_tdata;			//经过解调还原的 4KHz 正弦波
	wire				am_demod_tvalid;
	wire				am_demod_tready=1;

	am_modulation_dds	am_u1					//调幅波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调幅信号
	(
		.clk				(clk),				//1MHz
		.rst_n				(rst_n),			//复位
		.m_axis_data_tdata	(am_mod_tdata),		//调幅波数据输出, output wire [16 : 0]
		.m_axis_data_tvalid	(am_mod_tvalid),
		.m_axis_data_tready	(am_mod_tready)
	);

	am_fifo_demodulation_fir	am_u2				//调幅波解调模块,将调幅波解调还原调制信号
	(
		.clk				(clk),				//1MHz
		.clk_100mhz			(clk_100mhz),		//100MHz
		.rst_n				(rst_n),			//复位

		.s_axis_data_tdata	(am_mod_tdata),		//调幅信号输入 intput wire [16 : 0]
		.s_axis_data_tvalid	(am_mod_tvalid),
		.s_axis_data_tready	(am_mod_tready),

		.m_axis_data_tdata	(am_demod_tdata),	//调幅波解调数据输出, output wire [16 : 0]
		.m_axis_data_tvalid	(am_demod_tvalid),
		.m_axis_data_tready	(am_demod_tready)

	);

endmodule

实验四、FIR 高级应用 - AM 调幅波调制解调(FIR 低通滤波+重采样,FIR 高阶系数,FIR+FIFO )

1. AM 调幅波调制模块,请参考实验一

2. AM 调幅波解调模块(FIR 高级应用)

在这里插入图片描述

3. am_fifo_dc_demodulation_fir.v verilog 代码

//am_fifo_dc_demodulation_fir.v
module	am_fifo_dc_demodulation_fir
(
	input					rst_n,
	input					clk,
	input					clk_100mhz,
	input					s_axis_data_tvalid,
	output					s_axis_data_tready,
	input	signed[15:0]	s_axis_data_tdata,
	output					m_axis_data_tvalid,
	input					m_axis_data_tready,
	output	signed[15:0]	m_axis_data_tdata
);


	wire				clk_62_5khz;
	reg			[3:0]	clk_cnt		= 0;
	reg 		[15:0]	abs_data_r	= 0;
	reg					abs_valid_r	= 0;
	wire				abs_tready_i;

	assign	clk_62_5khz = clk_cnt[3];
	
	always @(posedge clk)
	begin
		clk_cnt	<= clk_cnt + 1;
	end
	
	always @(posedge clk)
	begin
		if(rst_n == 0 )
			abs_valid_r	<= 0;
		else if(abs_tready_i == 1)
			abs_valid_r	<= s_axis_data_tvalid;
	end

	always @(posedge clk)
	begin
		if(rst_n == 0 )
			abs_data_r	<= 0;
		else if(abs_tready_i == 1 && s_axis_data_tvalid == 1)
		begin
			if(s_axis_data_tdata >= 0)
				abs_data_r	<= s_axis_data_tdata;
			else
				abs_data_r	<= -s_axis_data_tdata;
		end
	end
	

	assign	s_axis_data_tready	= abs_tready_i;


	wire signed	[15:0]	fifo_as_tdata_i;
	wire				fifo_as_tvalid_i;
	wire				fifo_as_tready_i;
	wire				fifo_as_clk_i;

	wire signed	[15:0]	fifo_am_tdata_i;
	wire				fifo_am_tvalid_i;
	wire				fifo_am_tready_i;
	wire				fifo_am_clk_i;

	wire signed	[15:0]	fifo_bs_tdata_i;
	wire				fifo_bs_tvalid_i;
	wire				fifo_bs_tready_i;
	wire				fifo_bs_clk_i;

	wire signed	[15:0]	fifo_bm_tdata_i;
	wire				fifo_bm_tvalid_i;
	wire				fifo_bm_tready_i;
	wire				fifo_bm_clk_i;


	assign	fifo_as_clk_i		= clk;
	assign	fifo_am_clk_i		= clk_100mhz;
	assign	fifo_bs_clk_i		= clk_100mhz;
	assign	fifo_bm_clk_i		= clk_62_5khz;

	assign	fifo_as_tdata_i		= abs_data_r;
	assign	fifo_as_tvalid_i	= abs_valid_r;
	assign	abs_tready_i		= fifo_as_tready_i;
	
	axi_fifo_a16 fifo_ua
	(
		.wr_rst_busy	(),						// output wire wr_rst_busy
		.rd_rst_busy	(),						// output wire rd_rst_busy
		.m_aclk			(fifo_am_clk_i),		// input wire m_aclk
		.s_aclk			(fifo_as_clk_i),		// input wire s_aclk
		.s_aresetn		(rst_n),				// input wire s_aresetn
		.s_axis_tvalid	(fifo_as_tvalid_i),		// input wire s_axis_tvalid
		.s_axis_tready	(fifo_as_tready_i),		// output wire s_axis_tready
		.s_axis_tdata	(fifo_as_tdata_i),		// input wire [15 : 0] s_axis_tdata
		.m_axis_tvalid	(fifo_am_tvalid_i),		// output wire m_axis_tvalid
		.m_axis_tready	(fifo_am_tready_i),		// input wire m_axis_tready
		.m_axis_tdata	(fifo_am_tdata_i)		// output wire [15 : 0] m_axis_tdata
	);

	wire				fir_a_clk_i;
	wire				fir_b_clk_i;
	
	wire signed	[15:0]	fir_as_tdata_i;
	wire				fir_as_tvalid_i;
	wire				fir_as_tready_i;
	wire signed	[39:0]	fir_am_tdata_i;
	wire				fir_am_tvalid_i;
	wire				fir_am_tready_i;

	wire signed	[15:0]	fir_bs_tdata_i;
	wire				fir_bs_tvalid_i;
	wire				fir_bs_tready_i;
	wire signed	[39:0]	fir_bm_tdata_i;
	wire				fir_bm_tvalid_i;
	wire				fir_bm_tready_i;


	assign	fir_a_clk_i			= fifo_am_clk_i;
	assign	fir_b_clk_i			= fifo_am_clk_i;
	
	assign	fir_as_tvalid_i		= fifo_am_tvalid_i;
	assign	fir_as_tdata_i		= fifo_am_tdata_i;	// >>>17;
	assign	fifo_am_tready_i	= fir_as_tready_i;

	fir_compiler_lowpass_10k_30k_1m_dec	 am_fir_u1
	(
		.aresetn			(rst_n),			// input wire aresetn
		.aclk				(fir_a_clk_i),		// input wire aclk
		.s_axis_data_tvalid	(fir_as_tvalid_i),	// input wire s_axis_data_tvalid
		.s_axis_data_tready	(fir_as_tready_i),	// output wire s_axis_data_tready
		.s_axis_data_tdata	(fir_as_tdata_i),	// input wire [15 : 0] s_axis_data_tdata
		.m_axis_data_tvalid	(fir_am_tvalid_i),	// output wire m_axis_data_tvalid
		.m_axis_data_tready	(fir_am_tready_i),	// input wire m_axis_data_tready
		.m_axis_data_tdata	(fir_am_tdata_i)	// output wire [39 : 0] m_axis_data_tdata
	);

	assign	fir_bs_tvalid_i		= fir_am_tvalid_i;
	assign	fir_bs_tdata_i		= fir_am_tdata_i >>>19;
	assign	fir_am_tready_i		= fir_bs_tready_i;

	fir_compiler_highpass_30_50_62k am_fir_u2
	(
		.aresetn			(rst_n),			// input wire aresetn
		.aclk				(fir_b_clk_i),		// input wire aclk
		.s_axis_data_tvalid	(fir_bs_tvalid_i),	// input wire s_axis_data_tvalid
		.s_axis_data_tready	(fir_bs_tready_i),	// output wire s_axis_data_tready
		.s_axis_data_tdata	(fir_bs_tdata_i),	// input wire [15 : 0] s_axis_data_tdata
		.m_axis_data_tvalid	(fir_bm_tvalid_i),	// output wire m_axis_data_tvalid
		.m_axis_data_tready	(fir_bm_tready_i),	// input wire m_axis_data_tready
		.m_axis_data_tdata	(fir_bm_tdata_i)	// output wire [39 : 0] m_axis_data_tdata
	);

//	assign	fir_bm_tvalid_i		= fir_bs_tvalid_i;
//	assign	fir_bm_tdata_i		= fir_bs_tdata_i << 18;
//	assign	fir_bs_tready_i		= fir_bm_tready_i;


	assign	fifo_bs_tvalid_i	= fir_bm_tvalid_i;
	assign	fifo_bs_tdata_i		= fir_bm_tdata_i >>>16;
	assign	fir_bm_tready_i		= fifo_bs_tready_i;

	axi_fifo_a16 fifo_ub
	(
		.wr_rst_busy	(),						// output wire wr_rst_busy
		.rd_rst_busy	(),						// output wire rd_rst_busy
		.m_aclk			(fifo_bm_clk_i),		// input wire m_aclk
		.s_aclk			(fifo_bs_clk_i),		// input wire s_aclk
		.s_aresetn		(rst_n),				// input wire s_aresetn
		.s_axis_tvalid	(fifo_bs_tvalid_i),		// input wire s_axis_tvalid
		.s_axis_tready	(fifo_bs_tready_i),		// output wire s_axis_tready
		.s_axis_tdata	(fifo_bs_tdata_i),		// input wire [15 : 0] s_axis_tdata
		.m_axis_tvalid	(fifo_bm_tvalid_i),		// output wire m_axis_tvalid
		.m_axis_tready	(fifo_bm_tready_i),		// input wire m_axis_tready
		.m_axis_tdata	(fifo_bm_tdata_i)		// output wire [15 : 0] m_axis_tdata
	);
	
	assign	fifo_bm_tready_i	= m_axis_data_tready;
	assign	m_axis_data_tdata	= fifo_bm_tdata_i;
	assign	m_axis_data_tvalid	= fifo_bm_tvalid_i;
	
endmodule


4. am_fifo_dc_fir_testbench.v verilog 代码

///////////////////////////////////////////////////////////////////////

`timescale 1ns / 100ps
//am_fifo_dc_fir_testbench.v
module am_fifo_dc_fir_testbench;

reg			rst_n;
reg			clk;
reg			clk_100mhz;

parameter CLK_PERIOD		= 1000;		//1MHz
parameter CLK_PERIOD_100MHz	= 10;		//100MHz

initial	begin
	rst_n = 0;
	#(20 * CLK_PERIOD)
	rst_n = 1;
	#(80000 * CLK_PERIOD)
	$stop;
end

initial
	clk = 0;
always
begin
	clk = #(CLK_PERIOD/2.0) ~clk;
end

initial
	clk_100mhz = 0;
always
begin
	clk_100mhz = #(CLK_PERIOD_100MHz/2.0) ~clk_100mhz;
end

	wire signed	[15:0]	am_mod_tdata;			//调幅波数据,载波100KHz 正弦波,调制信号 4KHz 正弦波
	wire				am_mod_tvalid;
	wire				am_mod_tready;

	wire signed	[15:0]	am_demod_tdata;			//经过解调还原的 4KHz 正弦波
	wire				am_demod_tvalid;
	wire				am_demod_tready=1;

	am_modulation_dds	am_u1					//调幅波调制模块,生成 载波100KHz 正弦波,调制信号 4KHz 正弦波的调幅信号
	(
		.clk				(clk),				//1MHz
		.rst_n				(rst_n),			//复位
		.m_axis_data_tdata	(am_mod_tdata),		//调幅波数据输出, output wire [16 : 0]
		.m_axis_data_tvalid	(am_mod_tvalid),
		.m_axis_data_tready	(am_mod_tready)
	);

	am_fifo_dc_demodulation_fir	am_u2				//调幅波解调模块,将调幅波解调还原调制信号
	(
		.clk				(clk),				//1MHz
		.clk_100mhz			(clk_100mhz),		//100MHz
		.rst_n				(rst_n),			//复位

		.s_axis_data_tdata	(am_mod_tdata),		//调幅信号输入 intput wire [16 : 0]
		.s_axis_data_tvalid	(am_mod_tvalid),
		.s_axis_data_tready	(am_mod_tready),

		.m_axis_data_tdata	(am_demod_tdata),	//调幅波解调数据输出, output wire [16 : 0]
		.m_axis_data_tvalid	(am_demod_tvalid),
		.m_axis_data_tready	(am_demod_tready)

	);

endmodule

实验五、FIR 高级应用 - 多通道实验 (四个通道用一个 FIR IP,每通道用不同的系数)。

1. FIR 多通道模块(FIR 高级应用)

在这里插入图片描述

2. multichannel_fir.v verilog 代码

//multichannel_fir.v
module	multichannel_fir
(
	input					rst_n,
	input					clk,
	input					clk_100mhz,
	input					s_axis_data_tvalid,
	output					s_axis_data_tready,
	input	signed[63:0]	s_axis_data_tdata,
	output					m_axis_data_tvalid,
	input					m_axis_data_tready,
	output	signed[63:0]	m_axis_data_tdata
);

	wire 		[63:0]		fifo_as_tdata_i;
	wire					fifo_as_tvalid_i;
	wire					fifo_as_full_i;
	wire					fifo_as_clk_i;

	wire signed	[15:0]		fifo_am_tdata_i;
	wire					fifo_am_tvalid_i;
	wire					fifo_am_rden_i;
	wire					fifo_am_empty_i;
	wire					fifo_am_clk_i;

	wire signed	[15:0]		fifo_bs_tdata_i;
	wire					fifo_bs_tvalid_i;
	wire					fifo_bs_full_i;
	wire					fifo_bs_clk_i;

	wire signed	[63:0]		fifo_bm_tdata_i;
	wire					fifo_bm_tvalid_i;
	wire					fifo_bm_rden_i;
	wire					fifo_bm_empty_i;
	wire					fifo_bm_clk_i;

	assign	fifo_as_clk_i		= clk;
	assign	fifo_am_clk_i		= clk_100mhz;
	assign	fifo_bs_clk_i		= clk_100mhz;
	assign	fifo_bm_clk_i		= clk;

	assign	fifo_as_tdata_i		= s_axis_data_tdata;
	assign	fifo_as_tvalid_i	= s_axis_data_tvalid;
	assign	s_axis_data_tready	= ~fifo_as_full_i;
	assign	fifo_am_tvalid_i	= fifo_am_rden_i & ~fifo_am_empty_i;

	fifo_w64_r16 fifo_ua
	(
		.rst			(~rst_n),				// input wire rst
		.wr_clk			(fifo_as_clk_i),		// input wire wr_clk
		.rd_clk			(fifo_am_clk_i),		// input wire rd_clk
		.din			(fifo_as_tdata_i),		// input wire [63 : 0] din
		.wr_en			(fifo_as_tvalid_i),		// input wire wr_en
		.rd_en			(fifo_am_rden_i),		// input wire rd_en
		.dout			(fifo_am_tdata_i),		// output wire [15 : 0] dout
		.full			(fifo_as_full_i),		// output wire full
		.empty			(fifo_am_empty_i)		// output wire empty
	);

	wire				fir_a_clk_i;
	
	wire signed	[15:0]	fir_as_tdata_i;
	wire				fir_as_tvalid_i;
	wire				fir_as_tready_i;
	wire signed	[39:0]	fir_am_tdata_i;
	wire				fir_am_tvalid_i;
	wire				fir_am_tready_i;
	wire [1:0]			fir_am_tuser_i;

	wire [7:0]			fir_as_config_tdata_i;
	wire				fir_as_config_tvalid_i;
	wire				fir_as_config_tready_i;
	wire				fir_as_config_tlast_i;
	wire				event_s_config_tlast_missing_i;
	wire				event_s_config_tlast_unexpected_i;
	reg	[7:0]			s_cfg_cnt			= 0;
	reg	[7:0]			s_config_tdata_r	= 0;

	assign	fir_a_clk_i			= fifo_am_clk_i;
	assign	fir_as_tvalid_i		= fifo_am_tvalid_i;
	assign	fir_as_tdata_i		= fifo_am_tdata_i;
	assign	fifo_am_rden_i		= fir_as_tready_i;

	reg		[31:0]	time_cnt = 0;
	reg		[7:0]	channel_id_r	 = 0;
	wire	[31:0]	load_cfg;
	
	always @(posedge fir_a_clk_i)
	begin
		time_cnt	<= time_cnt + 1;
	end
	
	assign	load_cfg = ( time_cnt[14:0] == 15'h4000 && time_cnt > 'h8000 && time_cnt < 'h30000 ) ? 1:0;

	always @(posedge fir_a_clk_i)
	begin
		if(rst_n == 0)
		begin
			channel_id_r 	<= 0;
		end
		else if(fir_as_config_tlast_i == 1 && fir_as_config_tvalid_i == 1 && fir_as_config_tready_i == 1 && channel_id_r < 4)
		begin
			channel_id_r 	<= channel_id_r +1;
		end
	end

	always @(posedge fir_a_clk_i)
	begin
		if(load_cfg == 1)
		begin
			s_cfg_cnt 	<= 4;
			if(channel_id_r <4)
				s_config_tdata_r	<= 3 - channel_id_r;	//3/2/1/0 顺序
			else
				s_config_tdata_r	<= 0;
		end
		else if(fir_as_config_tready_i == 1 && fir_as_config_tvalid_i == 1 && s_cfg_cnt != 0)
		begin
			s_cfg_cnt 	<= s_cfg_cnt -1;
			if(channel_id_r ==4)
			begin
				s_config_tdata_r	<= s_config_tdata_r + 1;
			end
		end
	end
	
	assign	fir_as_config_tvalid_i	= s_cfg_cnt == 0 ? 0:1;
	assign	fir_as_config_tdata_i	= s_config_tdata_r;
	assign	fir_as_config_tlast_i	= s_cfg_cnt == 1 ? 1:0;

	fir_compiler_mc4_512 multichannel_fir_u1
	(
		.aresetn				(rst_n),				// input wire aresetn
		.aclk					(fir_a_clk_i),			// input wire aclk
		.s_axis_data_tvalid		(fir_as_tvalid_i),		// input wire s_axis_data_tvalid
		.s_axis_data_tready		(fir_as_tready_i),		// output wire s_axis_data_tready
		.s_axis_data_tdata		(fir_as_tdata_i),		// input wire [15 : 0] s_axis_data_tdata
		.s_axis_config_tvalid	(fir_as_config_tvalid_i),	// input wire s_axis_config_tvalid
		.s_axis_config_tready	(fir_as_config_tready_i),	// output wire s_axis_config_tready
		.s_axis_config_tlast	(fir_as_config_tlast_i),	// input wire s_axis_config_tlast
		.s_axis_config_tdata	(fir_as_config_tdata_i),	// input wire [7 : 0] s_axis_config_tdata
		.m_axis_data_tvalid		(fir_am_tvalid_i),		// output wire m_axis_data_tvalid
		.m_axis_data_tready		(fir_am_tready_i),		// input wire m_axis_data_tready
		.m_axis_data_tuser		(fir_am_tuser_i),		// output wire [1 : 0] m_axis_data_tuser
		.m_axis_data_tdata		(fir_am_tdata_i),		// output wire [39 : 0] m_axis_data_tdata
		.event_s_config_tlast_missing	(event_s_config_tlast_missing_i),		// output wire event_s_config_tlast_missing
		.event_s_config_tlast_unexpected(event_s_config_tlast_unexpected_i)	// output wire event_s_config_tlast_unexpected
	);
	assign	fifo_bs_tvalid_i	= fir_am_tvalid_i;
	assign	fifo_bs_tdata_i		= fir_am_tdata_i >>>24;
	assign	fir_am_tready_i		= ~fifo_bs_full_i;

	
	fifo_w16_r64 fifo_ub
	(
		.rst			(~rst_n),				// input wire rst
		.wr_clk			(fifo_bs_clk_i),		// input wire wr_clk
		.rd_clk			(fifo_bm_clk_i),		// input wire rd_clk
		.din			(fifo_bs_tdata_i),		// input wire [16 : 0] din
		.wr_en			(fifo_bs_tvalid_i),		// input wire wr_en
		.rd_en			(fifo_bm_rden_i),		// input wire rd_en
		.dout			(fifo_bm_tdata_i),		// output wire [63 : 0] dout

		.full			(fifo_bs_full_i),		// output wire full
		.empty			(fifo_bm_empty_i)		// output wire empty
	);

	assign	fifo_bm_rden_i		= m_axis_data_tready;
	assign	fifo_bm_tvalid_i	= fifo_bm_rden_i & ~fifo_bm_empty_i;

	assign	m_axis_data_tdata	= fifo_bm_tdata_i;
	assign	m_axis_data_tvalid	= fifo_bm_tvalid_i;

endmodule


3. multichannel_fir_testbench.v verilog 代码


///////////////////////////////////////////////////////////////////////

`timescale 1ns / 100ps
//multichannel_fir_testbench.v
module multichannel_fir_testbench;

reg			rst_n;
reg			ts;
reg			clk;
reg			clk_100mhz;
reg			clk_10khz;
reg			clk_30khz;
reg			clk_50khz;
reg			clk_70khz;

parameter CLK_PERIOD		= 476.1904762;		//2.1MHz
parameter CLK_PERIOD_100MHz	= 10;				//100MHz

parameter CLK_10K			= CLK_PERIOD * 210;
parameter CLK_30K			= CLK_PERIOD * 70;
parameter CLK_50K			= CLK_PERIOD * 42;
parameter CLK_70K			= CLK_PERIOD * 30;

initial	begin
	rst_n	= 0;
	ts		= 0;
	#(20 * CLK_PERIOD)
	rst_n	= 1;
	#(4500 * CLK_PERIOD)
	ts		= 1;
	#(1000 * CLK_PERIOD)
	$stop;
end

initial
begin
	clk			= 0;
	clk_100mhz	= 0;
	clk_10khz	= 0;
	clk_30khz	= 0;
	clk_50khz	= 0;
	clk_70khz	= 0;
end

always	clk			= #(CLK_PERIOD/2.0) ~clk;
always	clk_100mhz	= #(CLK_PERIOD_100MHz/2.0) ~clk_100mhz;
always	clk_10khz	= #(CLK_10K/2.0) ~clk_10khz;
always	clk_30khz	= #(CLK_30K/2.0) ~clk_30khz;
always	clk_50khz	= #(CLK_50K/2.0) ~clk_50khz;
always	clk_70khz	= #(CLK_70K/2.0) ~clk_70khz;


	wire 	signed[15:0]	s_tdata[3:0];
	wire					s_tvalid;
	wire					s_tready;

	wire 	signed[15:0]	m_tdata[3:0];
	wire					m_tvalid;
	wire					m_tready = 1;
	
		
	assign	s_tdata[0]  = clk_10khz == 0 ? -10000:10000;
	assign	s_tdata[1]  = ts == 0 ? {clk_30khz == 0 ? -10000:10000}:s_tdata[0];
	assign	s_tdata[2]  = ts == 0 ? {clk_50khz == 0 ? -10000:10000}:s_tdata[0];
	assign	s_tdata[3]  = ts == 0 ? {clk_70khz == 0 ? -10000:10000}:s_tdata[0];
	
	assign	s_tvalid = s_tready;

	multichannel_fir		u1
	(
		.clk				(clk),				//1MHz
		.clk_100mhz			(clk_100mhz),
		.rst_n				(rst_n),

		.s_axis_data_tdata	({s_tdata[0],s_tdata[1],s_tdata[2],s_tdata[3]}),
		.s_axis_data_tvalid	(s_tvalid),
		.s_axis_data_tready	(s_tready),

		.m_axis_data_tdata	({m_tdata[0],m_tdata[1],m_tdata[2],m_tdata[3]}),
		.m_axis_data_tvalid	(m_tvalid),
		.m_axis_data_tready	(m_tready)

	);

endmodule

4. fir_compiler_mc4_512 FIR IP 设置需要关注的地方

在这里插入图片描述

5. FIR 多通道实验时序图

在这里插入图片描述

6. FIR 多通道实验时序图CONFIG 时序细节放大

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验六、FIR 高级应用 FIR Reload的使用。

  • Reload 模块很简单只有一个 FIR IP 这里就不介绍框图了。把代码、时序时序贴出来看看。

1. reload_fir.v verilog 代码

//reload_fir.v
module	reload_fir
(
	input					rst_n,
	input					clk,
	input					s_axis_data_tvalid,
	output					s_axis_data_tready,
	input	signed[15:0]	s_axis_data_tdata,
	output					m_axis_data_tvalid,
	input					m_axis_data_tready,
	output	signed[15:0]	m_axis_data_tdata
);

	wire				fir_tlast_missing;
	wire				fir_tlast_unexpected;
	wire	[39:0]		m_axis_data_tdata_i;

	wire[15:0]		fir_reload_dat[3:0][127:0];
	reg	[15:0]		fir_dat0[127:0];
	reg	[15:0]		fir_dat1[127:0];
	reg	[15:0]		fir_dat2[127:0];
	reg	[15:0]		fir_dat3[127:0];


	wire [07:0]	fir_s_cfg_tdata;
	wire		fir_s_cfg_tvalid;
	wire		fir_s_cfg_tready;

	reg [15:0]	fir_s_reload_tdata;
	reg			fir_s_reload_tvalid;
	wire		fir_s_reload_tready;
	reg			fir_s_reload_tlast;
    
    genvar  m;

    for(m=0;m<128;m=m+1)
    begin:for_mx
        assign	fir_reload_dat[0][m]	= fir_dat0[m];
        assign	fir_reload_dat[1][m]	= fir_dat1[m];
        assign	fir_reload_dat[2][m]	= fir_dat2[m];
        assign	fir_reload_dat[3][m]	= fir_dat3[m];
    end

	initial
	begin
		$readmemh("../../../../../reload_bandpass_10k_30k_30k_50k_1m.txt",	fir_dat0);
		$readmemh("../../../../../reload_bandpass_30k_50k_50k_70k_1m.txt",	fir_dat1);
		$readmemh("../../../../../reload_bandpass_50k_70k_70k_90k_1m.txt",	fir_dat2);
		$readmemh("../../../../../reload_bandpass_70k_90k_90k_110k_1m.txt",	fir_dat3);
	end
		
	parameter	NUMBER_COE_SIZE = 128;	//64;
	parameter	NUMBER_COE_SETS = 2;	//
	
	reg	[15:0]	reload_cnt=16'hffff;
	reg	[15:0]	cfg_cnt=0;
	wire		reload_en;
	reg	[1:0]	reload_sn=0;
	reg[15:0]	fir_cntx=0;
	reg[15:0]	psel=0;
	reg[15:0]	w_psel=1;

	assign	fir_s_cfg_tdata		= psel;
	assign	fir_s_cfg_tvalid	= cfg_cnt == 0    ? 1:0;
	assign	reload_en			= fir_cntx[9:0] == 0 && fir_cntx != 0  ? 1:0;
	
	always @(posedge clk)
	begin
		if(rst_n == 0 )
		begin
			fir_s_reload_tdata	<= 0;
			fir_s_reload_tvalid	<= 0;
			fir_s_reload_tlast	<= 0;
		end
		else if(fir_s_reload_tready == 1)
		begin
			if(NUMBER_COE_SETS == 1)
			begin
			
				if(reload_cnt == NUMBER_COE_SIZE-1)
					fir_s_reload_tlast	<= 1;
				else
					fir_s_reload_tlast	<= 0;
			
				if(reload_cnt < NUMBER_COE_SIZE)
				begin
					fir_s_reload_tdata	<= fir_reload_dat[reload_sn][reload_cnt];
					fir_s_reload_tvalid	<= 1;
				end	
				else
				begin
					fir_s_reload_tdata	<= 0;
					fir_s_reload_tvalid	<= 0;
				end	
			end
			else
			begin
				if(reload_cnt == NUMBER_COE_SIZE)
					fir_s_reload_tlast	<= 1;
				else
					fir_s_reload_tlast	<= 0;

				if(reload_cnt<NUMBER_COE_SIZE+1)
				begin
					fir_s_reload_tvalid	<= 1;
					if(reload_cnt == 0)
						fir_s_reload_tdata	<= w_psel;
					else
						fir_s_reload_tdata	<= fir_reload_dat[reload_sn][reload_cnt-1];
				end	
				else
				begin
					fir_s_reload_tdata	<= 0;
					fir_s_reload_tvalid	<= 0;
				end
			end
		end
	end

	always @(posedge clk)
	begin
		if(rst_n == 0 )
		begin
			fir_cntx	<= 0;
		end
		else if(fir_s_reload_tready == 1 && fir_s_cfg_tready == 1)
		begin
			fir_cntx	<= fir_cntx + 1;
		end
	end

	always @(posedge clk)
	begin
		if(rst_n == 0 )
		begin
			reload_sn	<= 0;
			psel		<= 0;
		end
		else if(fir_s_reload_tlast == 1 && fir_s_reload_tready == 1)
		begin
			reload_sn	<= reload_sn + 1;
			psel		<= 1;
		end
	end


	always @(posedge clk)
	begin
		if(rst_n == 0 )
		begin
			reload_cnt		<= 16'hffff;
		end
		else if(reload_en == 1)
		begin
			reload_cnt		<= 0;
		end
		else if(fir_s_reload_tready == 1)
		begin
			if(reload_cnt != 16'hffff)
				reload_cnt	<= reload_cnt + 1;
		end
	end

	always @(posedge clk)
	begin
		if(rst_n == 0 ||(fir_s_reload_tlast == 1 && fir_s_reload_tready == 1))
		begin
			cfg_cnt		<= 0;
		end
		else if(fir_s_cfg_tready == 1)
		begin
			if(fir_s_cfg_tvalid == 1 || cfg_cnt != 16'hffff)
				cfg_cnt	<= cfg_cnt + 1;
		end
	end

	assign	m_axis_data_tdata = m_axis_data_tdata_i >> 18;

	reload_fir_256x2 am_fir_u1
	(
		.aresetn				(rst_n),					// input wire aresetn
		.aclk					(clk),						// input wire aclk
		.s_axis_config_tvalid	(fir_s_cfg_tvalid),			// input wire s_axis_config_tvalid
		.s_axis_config_tready	(fir_s_cfg_tready),			// output wire s_axis_config_tready
		.s_axis_config_tdata	(fir_s_cfg_tdata),			// input wire [7 : 0] s_axis_config_tdata
		.s_axis_reload_tvalid	(fir_s_reload_tvalid),		// input wire s_axis_reload_tvalid
		.s_axis_reload_tready	(fir_s_reload_tready),		// output wire s_axis_reload_tready
		.s_axis_reload_tlast	(fir_s_reload_tlast),		// input wire s_axis_reload_tlast
		.s_axis_reload_tdata	(fir_s_reload_tdata),		// input wire [15 : 0] s_axis_reload_tdata
		.s_axis_data_tvalid		(s_axis_data_tvalid),		// input wire s_axis_data_tvalid
		.s_axis_data_tready		(s_axis_data_tready),		// output wire s_axis_data_tready
		.s_axis_data_tdata		(s_axis_data_tdata),		// input wire [15 : 0] s_axis_data_tdata
		.m_axis_data_tvalid		(m_axis_data_tvalid),		// output wire m_axis_data_tvalid
		.m_axis_data_tready		(m_axis_data_tready),		// input wire m_axis_data_tready
		.m_axis_data_tdata		(m_axis_data_tdata_i),		// output wire [39 : 0] m_axis_data_tdata
		.event_s_reload_tlast_missing	(fir_tlast_missing),	// output wire event_s_reload_tlast_missing
		.event_s_reload_tlast_unexpected(fir_tlast_unexpected)	// output wire event_s_reload_tlast_unexpected
	);

endmodule


2. reload_fir_testbench.v verilog 代码


///////////////////////////////////////////////////////////////////////

`timescale 1ns / 100ps
//reload_fir_testbench.v
module reload_fir_testbench;

reg			rst_n;
reg			clk;
reg			clk_10khz;

parameter CLK_PERIOD		= 1000;		//1MHz 采样频率

parameter CLK_10K			= CLK_PERIOD * 100;

initial	begin
	rst_n	= 0;
	#(20 * CLK_PERIOD)
	rst_n	= 1;
	#(6000 * CLK_PERIOD)
	$stop;
end

initial
begin
	clk			= 0;
	clk_10khz	= 0;
end

always	clk			= #(CLK_PERIOD/2.0) ~clk;
always	clk_10khz	= #(CLK_10K/2.0) ~clk_10khz;


	wire 	signed[15:0]	s_tdata;
	wire					s_tvalid;
	wire					s_tready;

	wire 	signed[15:0]	m_tdata;
	wire					m_tvalid;
	wire					m_tready;
	

	assign	s_tdata  = clk_10khz == 0 ? -10000:10000;
	assign	s_tvalid = s_tready;
	assign	m_tready = 1;

	reload_fir am_fir_u1
	(
		.rst_n					(rst_n),					// input wire aresetn
		.clk					(clk),						// input wire aclk
		.s_axis_data_tvalid		(s_tvalid),					// input wire s_axis_data_tvalid
		.s_axis_data_tready		(s_tready),					// output wire s_axis_data_tready
		.s_axis_data_tdata		(s_tdata),					// input wire [15 : 0] s_axis_data_tdata
		.m_axis_data_tvalid		(m_tvalid),					// output wire m_axis_data_tvalid
		.m_axis_data_tready		(m_tready),					// input wire m_axis_data_tready
		.m_axis_data_tdata		(m_tdata)					// output wire [15 : 0] m_axis_data_tdata
	);

endmodule

3. FIR 高级应用 FIR Reload时序图

在这里插入图片描述

4. FIR 高级应用 FIR Reload细节时序图放大1

在这里插入图片描述

5. FIR 高级应用 FIR Reload细节时序图放大2

在这里插入图片描述

6. reload_fir FIR 高级应用 FIR IP 设置需要关注的地方1

在这里插入图片描述

7. reload_fir FIR 高级应用 FIR IP 设置需要关注的地方2

在这里插入图片描述

实验一、三综合布线后 FPGA 资源对比

实验一、三的AM解调部分单独综合布线后的FPGA资源占用报告

在这里插入图片描述

  • 实验一和实验三的区别
  • 实验一FIR IP 的工作时钟为 1MHz,AM 数据的采样频率为 1MHz 。
  • 实验三FIR IP 的工作时钟为 100MHz,AM 数据的采样频率为 1MHz 。在 FIR 前后加了两个 FIFO。
  • 从资源占用图可以看出 这两个 FIFO 只占用了 1 个 BRAM块(一个FIFO占用0.5个)。
  • 从资源占用图可以看出 实验三的资源占用远少于实验一,特别是 DSP 这种珍贵资源的的占用只有 1个。实验三只多了 1 个BRAM块。这样的交换是非常划算的。
  • 实验三仿真运行相比实验一非常慢

三、 实验相关 vivado 工程、IP 设置等详细文档连接,采用 Xilinx vivado 2017.4 版本

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老皮芽子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值