本白皮书概述了如何使用 IP 核 Moku 云编译,包括八个用于常见信号处理功能的预编译 IP 核以及定制的 AMD Vivado IP 核集成。每个 IP 核都提供了使用示例和使用 Moku 硬件的测试设置。该文档还指导用户上传定制 IP。
引言
Moku Cloud Compile 是一款功能强大的工具,可在 Moku 设备上使用。基于 Moku FPGA 的测试测量设备允许用户将自定义的 VHDL 和 Verilog 代码部署到硬件上。借助 Moku Cloud Compile,您可以将自己的设计与现有仪器集成,从而扩展和定制仪器功能,并利用 Moku 独特的片上仪器架构创造新功能。
Moku Cloud Compile 提供八个预编译 IP 核,针对算法、滤波、波形生成和相关性分析进行了优化,并与所有 Moku 设备兼容。这些 IP 核可立即实例化并简化常见的数字信号处理任务。用户还可以通过上传 AMD Vivado 创建的 IP 核,导入自己的 IP 核。 .xci 文件,从而可以将自定义硬件块无缝集成到 Moku Cloud Compile 设计中。
本文档概述了每个 IP 核的输入/输出端口、功能和示例用法,并提供了使用以下方法构建和测试定制设计的指导: 多仪器并行模式这些功能共同使 Moku Cloud Compile 成为一个更强大的平台,适用于快速原型设计和高级信号处理应用。
八个预编译IP核
本节介绍表 1 中列出的八个预编译 IP 核,详细说明其输入和输出端口规格及功能。每个 IP 核都提供了示例用例。由于这些 IP 核与 Moku Cloud Compile 后端原生集成,因此可以直接在用户设计中实例化,从而简化开发流程并降低实现成本。
表 1:八个预编译 IP 核的名称和描述。
| 序号 | IP核名称 | 描述 |
| 1 | 加减_16 | 动态可重构加法器/减法器模块。 |
| 2 | CIC_Dec_3Ordx8 | 级联积分器梳状 (CIC) 抽取器,抽取因子为 8,滤波器阶数为 3。 |
| 3 | Cordic_Translate_16 | 将 16 位实数和虚数输入转换为幅度和相位输出的转换器。 |
| 4 | Counter_32 | 32 位计数器支持加/减计数,具有同步清除功能。 |
| 5 | SineGen_48 | 具有 48 位频率步进分辨率的正弦和余弦波形发生器。 |
| 6 | FIR滤波器_7系数 | 具有固定系数的全速率 FIR 低通滤波器。 |
| 7 | FFT_1024 | 1,024 点快速傅里叶变换 (FFT) 块,可选择正向或逆向变换。 |
| 8 | FFT_65536 | 65,536 点快速傅里叶变换 (FFT) 块,具有可选正向或逆变换和可配置输出缩放。 |
1. AddSubtract_16
AddSubtract_16 模块实现了一个动态可配置的算术单元,能够对两个有符号的 16 位输入执行加法或减法运算。其操作遵循以下逻辑:
$latex S =left{ 开始{数组}{rl}
A + B 文本{(添加:HIGH)} \
A – B 文本{(添加:LOW)}
结束{array} 右。$
AddSubtract_16 内核的输入和输出端口详见表 2。输入总线(A 和 B)以及输出 (S) 均视为有符号的 16 位整数 (int16)。算术运算由 add 信号控制,而 ce(时钟使能)信号则用于启用或禁用模块的时钟。当 ce 保持高电平时,模块将持续处于活动状态。
表 2:AddSubtract_16 模块的端口定义,详细说明其输入和输出信号接口。
|
名称 |
方向性 | 描述 |
| A[15:0] | 输入 | 输入 A 总线。 |
| 乙[15:0] | 输入 | 输入B总线。 |
| CLK | 输入 | 时钟信号,上升沿。 |
| 加 | 输入 | 控制 AddSubtract_16 执行的操作。
(高 = 加法,低 = 减法) |
| ce | 输入 | 高电平有效时钟使能。设置为恒定高电平。 |
| 秒[15:0] | 输出 | 输出总线。 |
代码 1 提供了一个 VHDL 示例,演示如何使用 Control0 的第 0 位(最低有效位,LSB)实例化模块并进行控制。多仪器模式配置如图 1 所示。图 2 和图 3 所示的测试结果(使用 Moku 硬件进行)证实了在不同信号条件下减法和加法运算的正确性。
代码 1:VHDL 示例演示了 AddSubtract_16 模块的实例,其中 OutputA 表示 InputA + InputB 或 InputA – InputB 的结果,具体取决于 Control0 寄存器的 LSB 的状态。
LIBRARY ieee;
ARCHITECTURE Behavioral OF CustomWrapper IS
SIGNAL s_temp : STD_LOGIC_VECTOR(15 DOWNTO 0);
BEGIN
AddSubtract : AddSubtract_16
PORT MAP(
A => STD_LOGIC_VECTOR(InputA),
B => STD_LOGIC_VECTOR(InputB),
clk => clk,
-- use Control0's 0th bit to control the operation
add => Control0(0),
-- constant high clock enable
ce => '1',
S => s_temp
);
OutputA <= signed(s_temp);
END ARCHITECTURE;
图 1:使用多仪器模式的 AddSubtract_16 测试配置。在此设置中,Moku Cloud Compile 的输入 A 和输入 B 从 Moku 示波器的输出内部路由,而 Moku Cloud Compile 的处理后输出则反馈到示波器中。
如图 2 所示,Moku 示波器中的双通道嵌入式波形发生器配置为产生 5 kHz、500 mV 的正弦波和 100 Hz、5 Vpp 的锯齿波信号,对称性为 90%。将 Control0 的 LSB 设置为 0,Moku Cloud Compile 以减法模式运行。在 摩库示波器 确认了预期的减法器行为。随后,在图3中,将Control0的LSB设置为1,配置Moku Cloud Compile执行加法。结果输出确认了预期的加法器功能。
图 2:Moku Cloud Compile 使用两个输入信号输出减法结果:一个 500 mVpp、5 kHz 正弦波和一个 5 Vpp、100 Hz 斜波。将 Control0(0) 设置为 0,系统配置为以减法模式运行。
图 3:Moku Cloud Compile 输出响应 500 mVpp、5 kHz 正弦波和 5 Vpp、100 Hz 斜波。将 Control0(0) 设置为 1,系统配置为加法模式。
需要注意的是,AddSubtract_16 模块不包含进位机制,因此在算术运算过程中可能会发生溢出。具体来说,如果输入 A + 输入 B 的和超出有符号的 16 位范围 [-2^{15}, 2^{15}],则输出可能会因溢出而出现符号反转。
检测潜在溢出的常用方法是监控操作数的最高有效位 (MSB) 及其结果。如果输入符号相反,则不会发生溢出。但是,如果两个输入符号相同,而输出符号不同,则通常表示存在溢出。虽然本文承认存在此问题,但对溢出检测和缓解技术的详细讨论超出了本文的讨论范围。
输入源配置为 5 Vpp 正弦波和 5 V 直流信号。理论上,此组合应产生 2.5 V 至 7.5 V 范围内的输出波形。然而,Moku:Go 硬件的输入/输出范围限制为 ±5 V(10 Vpp)。因此,任何超出此范围的输出部分都会因溢出而发生符号反转。图 4 展示了这种现象,其中波形中原本应位于 5 V 至 7.5 V 之间的部分被卷绕并出现在 -2.5 V 至 -5 V 之间。
图 4:添加 5 Vpp、1 kHz 正弦波和 5 V 直流偏移会导致明显的溢出,因为信号超出了 Moku:Go 设备的 ±5 V 输入范围。将 Control0(0) 设置为 1 时,系统以加法模式运行,输出中的符号反转确认了溢出的发生。
2. CIC_Dec_3Ordx8
CIC_Dec_3Ordx8 模块实现了一个三阶级联积分梳状 (CIC) 抽取滤波器,其固定抽取率为 3。CIC 滤波器广泛用于需要降低高采样率的多速率系统。该架构仅依赖于加法器、减法器和延迟器,非常适合数字接收器和锁相放大器等硬件高效的下采样应用。
表 3 总结了模块的输入和输出端口,表 4 提供了延迟和滤波器阶数等实现细节。该模块接受 16 位有符号输入样本,并产生 25 位有符号输出样本。输入接口为输入和输出通道提供握手信号 (tvalid, tready)。滤波器仅在收到有效输入且内核准备就绪时才更新其输出。
表 3:CIC_Dec_3Ordx8 IP 核的端口描述。
| 名称 | 方向性 | 描述 |
| 时钟 | 输入 | 时钟信号,上升沿。 |
| s_axis_data_tdata [15:0] | 输入 | TDATA 代表数据输入通道。承载未处理的样本数据。 |
| s_axis_data_tvalid | 输入 | 数据输入通道的 TVALID。外部模块使用它来表示其能够提供数据。 |
| s_axis_data_tready | 输出 | 数据输入通道的 TREADY。CIC 抽取器使用它来表示已准备好接受数据。 |
| m_axis_data_tdata [24:0] | 输出 | TDATA 为数据输出通道。承载已处理好的样本数据。 |
| m_axis_data_tvalid | 输出 |
TVALID 表示数据输出通道。由 CIC 抽取器置位,表示其能够提供样本数据。 |
表4:CIC_Dec_3Ordx8 IP核的配置参数。
|
组件名称 |
CIC_Dec_3Ordx8 |
| 过滤器类型 | 抽取 |
| 阶段数 | 3 |
| 差分延迟 | 1 |
| 支持的速率 | 8 |
| 输入采样频率(MSa/s) | 31.25 |
| 时钟频率 (MHz) | 31.25 |
| 输入数据宽度 | 16 |
| 输出数据宽度 | 25 |
| 延迟 |
15 |
在代码 2 所示的 VHDL 示例中,仅当内核就绪(s_axis_data_tready 为高电平)时才会写入输入数据,并且仅当有效数据可用(m_axis_data_tvalid 为高电平)时才会捕获输出。输出通过截断至最高 16 位进行缩放,以保持与输入动态范围的一致性。需要注意的是,有效信号必须置位,并且仅当该信号为高电平时才应更新输出。否则,输出可能会呈现脉冲或间歇性行为,而不是连续的数据流。这是因为 CIC_Dec_3Ordx8 根据其抽取因子,每八个时钟周期生成一个有效输出样本。
代码 2:VHDL 示例,演示了具有 8 倍抽取因子的 CIC 抽取器的实例化。信号 OutputA 表示信号 InputA 的下采样版本。
LIBRARY ieee;
ARCHITECTURE Behavioral OF CustomWrapper IS
SIGNAL s_axis_data_tready : STD_LOGIC;
SIGNAL s_axis_data_tdata : STD_LOGIC_VECTOR(15 DOWNTO 0);
SIGNAL m_axis_data_tvalid : STD_LOGIC;
SIGNAL m_axis_data_tdata : STD_LOGIC_VECTOR(31 DOWNTO 0);
BEGIN
Decimator : CIC_Dec_3Ordx8
PORT MAP(
aclk => clk,
s_axis_data_tdata => s_axis_data_tdata,
s_axis_data_tvalid => '1', -- always output
s_axis_data_tready => s_axis_data_tready,
m_axis_data_tdata => m_axis_data_tdata,
m_axis_data_tvalid => m_axis_data_tvalid
);
PROCESS (clk)
BEGIN
IF rising_edge(clk) THEN
-- update input data when CIC is ready
IF s_axis_data_tready THEN
s_axis_data_tdata <= STD_LOGIC_VECTOR(InputA);
ELSE
s_axis_data_tdata <= (OTHERS => '0');
END IF;
-- update Output only when data is valid
IF m_axis_data_tvalid THEN
-- Scale data correctly
OutputA <= signed(m_axis_data_tdata(24 DOWNTO 9));
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
多仪器模式测试设置使用 Moku 频率响应分析仪 评估滤波器频率响应的方法如图5所示。CIC滤波器的频率响应尤其值得关注,因为它表征了带外信号的衰减,并反映了其在抽取过程中抑制混叠噪声的有效性。图6和图7中的测量结果与理论预期结果吻合良好,这解释了抽取和插值伪像造成的预期差异。
图 5:多仪器模式测试配置,其中使用 Moku 频率响应分析仪分析 Moku Cloud Compile 输出。
图 6:使用 Moku 频率响应分析仪获得的 CIC_Dec_3Ordx8 IP 核的频率响应。
图 7:CIC_Dec_3Ordx8 的模拟响应和实现响应之间的比较。
3. Cordic_Translate_16
CORDIC 核实现了坐标旋转数字计算机 (CORDIC) 算法,这是一种用于计算三角函数的迭代方法,更广泛地说,用于求解涉及双曲函数和平方根运算的方程。表 5 提供了输入和输出端口描述。Cordic_Translate_16 核将输入信号从笛卡尔表示(实部和虚部)转换为相应的极坐标形式(幅度和相位)。该模块的总计算延迟为 20 个时钟周期。
表5:Cordic_Translate_16 IP核的端口定义。
|
名称 |
方向性 | 描述 |
| 时钟 | 输入 | 时钟。有效上升沿。 |
| s_axis_cartesian_tvalid | 输入 | 通道 S_AXIS_CARTESIAN 的握手信号。 |
| s_axis_cartesian_tdata [31:0] | 输入 | 根据功能配置,此端口具有一个或两个子字段。
X_IN 和 Y_IN,X_IN 为 [15:0],Y_IN 为 [31:16]。这些是笛卡尔操作数。 每个子字段宽16位。X_IN和Y_IN均有14个小数位和2个整数位。 |
| m_axis_dout_tvalid | 输出 | 输出通道的握手信号。 |
| m_axis_dout_t数据 [31:0] | 输出 |
根据功能配置,此端口包含以下子字段:AMPLITUDE_OUT、PHASE_OUT。 AMPLITUDE_OUT 为 [15:0],PHASE_OUT 为 [31:16]。 每个子字段宽16位。AMPLITUDE_OUT有14个小数位和2个整数位。PHASE_OUT有13个小数位和3个整数位,单位为弧度。 |
Cordic_Translate_16 IP 核可以使用代码 3 进行实例化,它将信号的虚部(InputA)和实部(InputB)转换为其相应的幅度(OutputA)和相位角(OutputB)。
代码 3:VHDL 实现示例,演示 Cordic_Translate_16 IP 核的实例化。
LIBRARY ieee;
ARCHITECTURE Behavioral OF CustomWrapper IS
SIGNAL m_axis_dout_tvalid : STD_LOGIC;
SIGNAL tdata_temp : signed(31 DOWNTO 0);
BEGIN
Cordic : Cordic_Translate_16
PORT MAP(
aclk => clk,
-- input is always valid
s_axis_cartesian_tvalid => '1',
-- InputA : imaginary part
-- InputB : real part
s_axis_cartesian_tdata => STD_LOGIC_VECTOR(InputA & InputB),
m_axis_dout_tvalid => m_axis_dout_tvalid,
m_axis_dout_tdata => tdata_temp
);
PROCESS (clk)
BEGIN
IF rising_edge(clk) THEN
IF m_axis_dout_tvalid THEN
OutputA <= signed(tdata_temp(15 DOWNTO 0));
OutputB <= signed(tdata_temp(31 DOWNTO 16));
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
使用图 16 所示的多仪器模式设置对实例化的 Cordic_Translate_8 进行测试。Moku Cloud Compile 的 InputA(虚部)和 InputB(实部)从 Moku 示波器输出内部路由到 Moku Cloud Compile,后者计算相应的幅度和相位输出。这些 Moku Cloud Compile 输出随后被路由回示波器进行可视化和分析。
结果如图9所示。蓝色曲线达到峰值3.9288 V,对应约3.1415弧度。由于相位输出用13位小数表示,因此分辨率为2^13 LSB/弧度。要将数字值转换为物理单位,必须确定Moku Cloud Compile的数字分辨率,具体方法如下: 开始假设 Moku:Go 的数字分辨率为 6550.4 LSBs/V,则弧度值的计算方法如下:
\(frac{text{3.9288 V} 乘以 text{6550.4 LSBs/V}}{2^{13} text{LSBs/rad}}=text{3.1415 rad}\)
此外,由于 Cordic_Translate_1.1644 执行的 20 次迭代期间引入的缩放效应的累积,幅度输出的幅度增加了约 16 倍。
图 8:用于测试 Cordic_Translate_16 IP 核的多仪器模式测试设置。
图 9:两个输出通道配置为 100 Hz 正弦波,相位偏移 5°,频率为 90 Vpp,用于模拟连续旋转的复矢量。输入 A(红色轨迹)表示幅度,输入 B(蓝色轨迹)表示相位。正如预期的那样,幅度保持不变,而相位随时间线性增加,每 2𝜋 弧度旋转一次。
4. Counter_32
Counter_32 IP 核提供利用查找表 (LUT) 和单个 DSP Slice 实现的计数器。输入和输出端口功能如表 6 所示。它支持加/减计数模式,输出宽度为 32 位。计数器在每个时钟周期递增 XNUMX,并可通过拉高 SCLR 信号同步清零。
表6:Counter_32的端口定义。
| 名称 | 方向性 | 描述 |
| CLK | 输入 | 上升沿时钟信号。 |
| 顺铂 | 输入 | 同步清除:当输出为高电平时,强制输出为低电平状态。 |
| UP | 输入 | 控制加/减计数器的计数方向。高电平时加计数,低电平时减计数。 |
| 问 [31:0] | 输出 |
计数器输出。32位宽。 |
代码 4 中的示例实现了两个 Counter_32 函数:一个配置为双向计数以生成三角波,另一个配置为单向计数以产生锯齿波。由于该设计的工作范围低于 16,因此只有计数器的最低 65,536 位有效位连接到输出。
代码 4:实例化两个 Counter_32 用于三角波和锯齿波的 VHDL 示例。
LIBRARY ieee;
ARCHITECTURE Behavioural OF CustomWrapper IS
SIGNAL sclr_triangular : STD_LOGIC;
SIGNAL sclr_sawtooth : STD_LOGIC;
SIGNAL up_triangular : STD_LOGIC;
SIGNAL up_sawtooth : STD_LOGIC;
SIGNAL q_triangular : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL q_sawtooth : STD_LOGIC_VECTOR(31 DOWNTO 0);
BEGIN
-- Triangular wave
Triangular : Counter_32
PORT MAP(
clk => clk,
-- synchronous clear
sclr => sclr_triangular,
up => up_triangular,
q => q_triangular
);
OutputA <= signed(q_triangular(15 DOWNTO 0));
-- Triangular counter configuration
PROCESS (clk) IS
BEGIN
IF rising_edge(clk) THEN
-- reset
IF Control0(0) = '1' THEN
sclr_triangular <= '1';
up_triangular <= '1';
ELSE
-- don't clear
sclr_triangular <= '0';
-- Control1: counter limit
IF q_triangular = Control1 THEN
-- count down
up_triangular <= '0';
ELSIF q_triangular = x"00000000" THEN
-- count up
up_triangular <= '1';
ELSE
-- hold
up_triangular <= up_triangular; END IF; END IF; END IF; END PROCESS; Sawtooth : Counter_32 PORT MAP( clk => clk,
sclr => sclr_sawtooth, -- synchronous clear
up => up_sawtooth,
q => q_sawtooth
);
OutputB <= signed(q_sawtooth(15 DOWNTO 0));
-- Sawtooth counter configuration
PROCESS (clk) IS
BEGIN
IF rising_edge(clk) THEN
-- reset
IF Control0(0) = '1' THEN
sclr_sawtooth <= '1';
up_sawtooth <= '1';
ELSE
-- always count up
up_sawtooth <= '1';
-- Control2 : counter limit
IF q_sawtooth = Control2 THEN
-- clear
sclr_sawtooth <= '1';
ELSE
-- continue counting
sclr_sawtooth <= '0';
END IF;
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
多仪器模式配置如图 10 所示。使用 Moku 示波器可视化两个 Counter_32 模块产生的波形。两个计数器的控制值均通过 Control6,550 和 Control1 配置为 2,基于 Moku:Go 1 LSB/V 的数字分辨率,峰值输出约为 6550.4 V。Control0 的 LSB 用作复位信号,必须在操作前将其设置为高电平,然后再设置为低电平。正如预期的那样,锯齿波的频率是三角波的两倍,因为它只向上计数,而三角波则在向上和向下计数周期之间交替。
测试结果如图 11 所示。红色轨迹表示三角波形,由交替向上和向下计数产生。蓝色轨迹表示锯齿波形,该波形持续递增,并在达到配置的 6,550 限值时重置。
图 10:用于测试 Counter_32 的多仪器模式配置。
图11:Moku Cloud Compile控制寄存器的配置以及两个Counter_32模块的对应输出。
5. SineGen_48
SineGen_48 IP 核可生成高分辨率、低失真的正弦波形。其输入和输出端口详见表 7。它接受 48 位频率阶跃输入,并通过 16 位输出端口产生 32 位正弦和余弦输出。该模块可用作正弦波形发生器子模块,适用于各种高级应用,包括锁相环以及同时进行幅度和频率调制(AM 和 FM)。
由于 SineGen_48 IP 核需要 48 位频率步进输入,而 Moku Cloud Compile 的控制寄存器限制为 32 位,因此必须将两个寄存器组合起来才能形成完整的 48 位输入。例如,在代码 5 中,Control16 的最低有效 2 位与 Control32 的 1 位连接起来,构成完整的频率控制字。生成的输出被分成两个 16 位分量,分别对应正弦和余弦波形,并分别路由至 OutputA 和 OutputB。此外,内部相位计数器的最高有效 16 位被定向至 OutputC。
代码5:SineGen_48的VHDL实例化示例。
LIBRARY ieee;
ARCHITECTURE Behavioural OF CustomWrapper IS
SIGNAL m_axis_data_tvalid : STD_LOGIC;
SIGNAL m_axis_phase_tvalid : STD_LOGIC;
SIGNAL sine_temp : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL m_axis_phase_tdata : STD_LOGIC_VECTOR(47 DOWNTO 0);
BEGIN
SineCosineGen : SineGen_48
PORT MAP(
aclk => clk,
-- Use the 0th bit of Control0 to reset this module
aresetn => NOT Control0(0),
-- input signal is always available
s_axis_config_tvalid => '1',
-- 48-bit frequency step
s_axis_config_tdata => Control2(15 DOWNTO 0) & Control1,
m_axis_data_tvalid => m_axis_data_tvalid,
m_axis_data_tdata => sine_temp,
m_axis_phase_tvalid => m_axis_phase_tvalid,
m_axis_phase_tdata => m_axis_phase_tdata -- 48-bit phase counter output
);
-- only output data when data is valid
PROCESS (clk)
BEGIN
IF rising_edge(clk) THEN
IF m_axis_data_tvalid THEN
-- 32-bit, the most significant 16 bits are sine
-- and the least significant 16 bits are cosine
OutputA <= signed(sine_temp(15 DOWNTO 0));
OutputB <= signed(sine_temp(31 DOWNTO 16));
END IF;
IF m_axis_phase_tvalid THEN
OutputC <= signed(m_axis_phase_tdata(47 DOWNTO 32));
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
用于测试 SineGen_48 IP 核的多仪器模式配置如图 12 所示。通过将 Control3.125 配置为 1、将 Control2,374,548,092 配置为 2,频率步长设置为 6 kHz。完整的 48 位频率控制字计算如下:
\(文本{频率步长} = 文本{控制 2} 乘以 2^{32} + 文本{控制 1} = 2,814,749,767\)
以 Hz 为单位的频率可以计算如下:
\(text{频率} = frac{text{时钟频率}}{2^{48}} 乘以 [text{控制 2} 乘以 2^{32} + text{控制 1}]\)
假设 Moku:Go 时钟频率为 31.25 MHz,则输出频率变为 3.125 kHz。
图 12:用于测试 SineGen_48 IP 核的多仪器模式配置。
图 13 显示了 SineGen_48 IP 核的输出,其中通道 A(红色)表示余弦波形,通道 B(蓝色)表示正弦波形。测得两个信号之间的相位差为 90°,符合预期。此外,图 14 展示了 Moku Cloud Compile 路由到 OutputC 的相位计数器的行为。输出呈现连续上升的斜坡,证实了相位信号以与生成的余弦波形相同的频率前进。
图 13:使用 Moku 示波器可视化的正弦和余弦波形。通道 A(红色)显示余弦信号,通道 B(蓝色)显示正弦信号。频率步进配置为:控制 1 设置为 2,374,548,092,控制 2 设置为 6。
图 14:Moku 示波器输入连接到 Moku Cloud Compile 的 OutputA 和 OutputC。蓝色轨迹表示相位计数器输出的最高 16 位。
6. FIR_滤波器_7系数
FIR_Filter_7coef IP 核以固定系数全时钟速率运行,为需要将低通滤波器集成到 Moku Cloud Compile 设计中且无需在多仪器模式设置中使用额外仪器的用户提供了一种资源高效的解决方案。滤波器系数列于表 8,端口定义列于表 9。
对于需要可调系数的应用,用户可以使用 Moku FIR 滤波器生成器 或者按照以下指南重新编译自定义FIR滤波器IP核 定制IP核 本文的部分。
表 8:FIR_Filter_7coef 中使用的系数。
表 9:FIR_Filter_7coef 的端口定义。
| 名称 | 方向性 | 描述 |
| 时钟 | 输入 | 上升沿时钟。 |
| s_axis_data_tvalid | 输入 | 输入数据通道的tvalid。由外部模块置位,表示数据可供传输。 |
| s_axis_data_tready | 输出 | 输入数据通道已准备好。由内核置位,表示内核已准备好接收数据。 |
| s_axis_data_tdata [15:0] | 输入 | tdata 为输入数据通道。传输需要过滤的数据流。请参阅 tdata 结构体了解其内部结构。 |
| m_axis_data_tvalid | 输出 | tvalid 用于输出数据通道。由内核置位,表示数据可供传输。 |
| m_axis_data_tdata [23:0] | 输出 | tdata 表示输出数据通道。这是已过滤的数据流。请参阅 tdata 结构体了解其内部结构。 |
FIR_Filter_7coef IP 核的 VHDL 实例化在代码 6 中提供。本例中省略了握手信号,因为该滤波器设计用于处理连续输入数据并产生连续输出流。为了确保正确的输出缩放,滤波器输出的最高 16 位有效位被路由至 OutputA。
本应用说明探讨了双 Boxcar 平均器的实现,概述了其核心结构,该结构由四个单 Boxcar 平均器组组成
代码 6:实例化 FIR_Filter_7coef IP 核的 VHDL 示例。
LIBRARY ieee;
ARCHITECTURE Behavioural OF CustomWrapper IS
SIGNAL FIR_out_temp : STD_LOGIC_VECTOR(23 DOWNTO 0);
BEGIN
FIR_Filter : FIR_Filter_7coef
PORT MAP(
aclk => clk,
-- input data is always valid
s_axis_data_tvalid => '1',
-- FIR filter ready to accept data
s_axis_data_tready => OPEN,
s_axis_data_tdata => InputA,
-- FIR filtered data is available to be transferred
m_axis_data_tvalid => OPEN,
m_axis_data_tdata => FIR_out_temp
);
OutputA <= signed(FIR_out_temp(23 DOWNTO 8));
END ARCHITECTURE;
FIR_Filter_7coef 多仪器模式测试设置如图 15 所示。Moku 频率响应分析仪测得的滤波器响应如图 16 所示。模拟响应与测量响应的比较如图 17 所示。 
图 15:FIR_Filter_7coef IP 核的多仪器模式配置。
图 16:使用 Moku 频率响应分析仪获得的频率响应。
图 17:基于给定 FIR 系数的模拟响应与测量的频率响应之间的比较。
7. FFT_1024
快速傅里叶变换 (FFT) IP 核实现了 Cooley-Tukey 算法,这是一种高效的离散傅里叶变换 (DFT) 计算技术。它非常适合大规模滤波、互相关和粗略频率分析等应用。表 10 提供了 FFT_1024 的输入和输出定义。本节介绍 FFT 核的示例实现。
表10:FFT_1024 IP核的端口定义。
| 名称 | 方向性 | 描述 |
| 时钟 | 输入 | 上升沿时钟。 |
| 阿雷森 | 输入 | 低电平有效同步清零(可选,始终优先于 aclken)。至少需要两个周期的 aresetn 有效脉冲。 |
| s_axis_config_tdata[7:0] | 输入 | tdata 用于配置通道。包含以下配置信息:CP_LEN、FWD/INV、NFFT 和 SCALE_SCH。
仅最低有效位(第 0 位)用于控制 FWD/INV(正向或反向 FFT)。其他位为空。 |
| s_axis_config_tvalid | 输入 | tvalid 用于配置通道。由外部模块置位,表示其能够提供数据。 |
| s_axis_config_tready | 输出 | tready,用于配置通道。由内核置位,表示已准备好接受配置数据。 |
| s_axis_data_tdata[31:0] | 输入 | tdata 为数据输入通道。承载未处理的样本数据:实部为[15:0],虚部为[31:16]。 |
| s_axis_data_tvalid | 输入 | 数据输入通道的 tvalid。外部模块使用它来表示其能够提供数据。它可以设置为恒定高电平。 |
| s_axis_data_tready | 输出 | tready 表示数据输入通道。内核使用它来表示已准备好接收数据。 |
| s_axis_data_tlast | 输入 | tlast 为数据输入通道。由外部模块在帧的最后一个样本上置位。内核不使用它,除非生成 event_tlast_unexpected 和 event_tlast_missing 事件。 |
| m_axis_data_tdata[63:0] | 输出 | tdata 为数据输出通道。承载处理后的样本数据,实部为 [58:32],虚部为 [26:0]。信号均为有符号的 27 位数据,小数部分为 15 位。 |
| m_axis_data_tuser[15:0] | 输出 | tuser 表示数据输出通道。包含每个样本信息的索引。 |
| m_axis_data_tvalid | 输出 | tvalid 表示数据输出通道。由内核置位,表示其能够提供样本数据。 |
| m_axis_data_tready | 输入 | tready 表示数据输出通道。由外部从设备置位,表示其已准备好接收数据。 |
| m_axis_data_tlast | 输出 | tlast 为数据输出通道。由内核在帧的最后一个样本处置位。 |
| 事件框架已启动 | 输出 | 当核心开始处理新帧时断言。 |
| event_tlast_unexpected | 输出 | 当核心在非帧中最后一个数据样本上看到 s_axis_data_tlast 高时断言。 |
| 事件上次丢失 | 输出 | 当 s_axis_data_tlast 在一帧的最后一个数据样本上为低时断言。 |
| 事件状态通道停止 | 输出 | 当核心尝试将数据写入状态通道但无法执行时,发出断言。 |
| 事件数据进入通道暂停 | 输出 | 当核心从数据输入通道请求数据但没有可用数据时,发出断言。 |
| 事件数据输出通道停止 | 输出 | 当核心尝试将数据写入数据输出通道但无法执行时,发出断言。 |
代码 1024 中提供了 FFT_7 IP 核的 VHDL 实例。由于输入信号是纯实数,因此只有 s_axis_data_tdata 的最低有效 16 位连接到 InputA,而 FFT 输出的实部和虚部的最高有效 16 位连接到 Cordic_Translate_16 模块的输入,该模块计算相应的幅度和相位。
在此示例中,通过将 s_axis_config_tdata 的 LSB 设置为高,FFT 通过硬编码设置配置为正向傅里叶变换。事件信号特意保持未连接状态,因为在本示例中未使用它们。每个 FFT 帧的结束由 m_axis_data_tlast 信号指示,此时 FFT 核心会重置以准备下一个处理周期。
为了解决 Cordic_Translate_20 的 16 周期处理延迟,FFT 输出索引 (m_axis_data_tuser) 会相应延迟。最终的幅度、相位和频率点索引分别路由至 OutputA、OutputB 和 OutputC。
代码 7:VHDL 示例,演示了 FFT_1024 IP 核与 Cordic_Translate_16 模块的实例化,用于将 FFT 输出转换为相应的幅度和相位值。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
ARCHITECTURE Behavioural OF CustomWrapper IS
TYPE array_tuser IS ARRAY (0 TO 19) OF signed(15 DOWNTO 0);
SIGNAL aresetn, aresetn_dly : STD_LOGIC;
SIGNAL s_axis_data_tdata : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL s_axis_data_tready : STD_LOGIC;
SIGNAL m_axis_data_tlast : STD_LOGIC;
SIGNAL m_axis_data_tvalid, m_axis_data_tvalid_dly : STD_LOGIC;
SIGNAL m_axis_data_tuser : signed(15 DOWNTO 0);
SIGNAL m_axis_data_tuser_dly : array_tuser;
SIGNAL m_axis_dout_tvalid : STD_LOGIC;
SIGNAL tdata_temp : signed(31 DOWNTO 0);
SIGNAL im, real : STD_LOGIC_VECTOR(26 DOWNTO 0);
SIGNAL fftdata_temp : STD_LOGIC_VECTOR(63 DOWNTO 0);
BEGIN
FFT_DUT : FFT_1024
PORT MAP(
aclk => clk,
aresetn => (NOT reset) AND aresetn AND aresetn_dly,
-- Forward FFT with the LSB configured as 1
s_axis_config_tdata => x"01",
-- Config data is always valid
s_axis_config_tvalid => '1',
-- Leave config ready signal open
-- config data is constant
s_axis_config_tready => OPEN,
-- Input only has real values
s_axis_data_tdata => s_axis_data_tdata,
-- Input data is always valid
s_axis_data_tvalid => '1',
-- Data ready logic
s_axis_data_tready => s_axis_data_tready,
-- Continuous data stream
-- don't have last sample
s_axis_data_tlast => '0',
-- Transformed data
m_axis_data_tdata => fftdata_temp,
-- FFT frequency index
m_axis_data_tuser => m_axis_data_tuser,
-- output is valid
m_axis_data_tvalid => m_axis_data_tvalid,
-- Slave device is always ready to accept output
m_axis_data_tready => '1',
-- last sample of the frame
m_axis_data_tlast => m_axis_data_tlast,
-- don't care events
event_frame_started => OPEN,
event_tlast_unexpected => OPEN,
event_tlast_missing => OPEN,
event_status_channel_halt => OPEN,
event_data_in_channel_halt => OPEN,
event_data_out_channel_halt => OPEN
);
-- only output data when data is valid
PROCESS (clk)
BEGIN
IF rising_edge(clk) THEN
IF s_axis_data_tready THEN
s_axis_data_tdata <= x"0000" & STD_LOGIC_VECTOR(InputA);
END IF;
IF m_axis_data_tvalid THEN
im <= fftdata_temp(58 DOWNTO 32);
real <= fftdata_temp(26 DOWNTO 0);
END IF;
m_axis_data_tuser_dly <= m_axis_data_tuser & m_axis_data_tuser_dly(0 TO 18);
END IF;
END PROCESS;
-- reset process
-- reset fft when the tlast is high
PROCESS (clk)
BEGIN
IF rising_edge(Clk) THEN
aresetn_dly <= aresetn;
IF m_axis_data_tlast THEN
aresetn <= '0';
ELSE
aresetn <= '1'; END IF; END IF; END PROCESS; Cordic : Cordic_Translate_16 PORT MAP( aclk => clk,
s_axis_cartesian_tvalid => m_axis_data_tvalid,
s_axis_cartesian_tdata => STD_LOGIC_VECTOR(im(26 DOWNTO 11) & real(26 DOWNTO 11)),
m_axis_dout_tvalid => m_axis_dout_tvalid,
m_axis_dout_tdata => tdata_temp
);
PROCESS (clk)
BEGIN
IF rising_edge(clk) THEN
IF m_axis_dout_tvalid THEN
OutputA <= signed(tdata_temp(15 DOWNTO 0));
OutputB <= signed(tdata_temp(31 DOWNTO 16));
OutputC <= signed(m_axis_data_tuser_dly(19));
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
多仪器模式测试配置和相应的输出信号如图 18 和图 19 所示。图 18 说明了 FFT_1024 和 Cordic_Translate_16 IP 核的幅度输出的测量设置,而图 19 显示了捕获相位输出的配置。
在图 18 中,幅度谱中可见两个峰值,一个位于正频率范围内,另一个位于负频率范围内。与正频率峰值相关的索引对应于相对于索引斜坡起始点的时间戳。假设 Moku:Go 时钟工作频率为 31.25 MHz,索引斜坡的总时间跨度为 32.684 微秒,则估计频率计算如下:
![]()
\(文本{频率} = frac{文本{10.531 } mu 文本{s}}{文本{32.684 } mu 文本{s}} 乘以文本{31.25 MHz} = 文本{10.0689 MHz}\)
值得注意的是,1024点FFT的分辨率带宽约为0.03 MHz。因此,此实现仅适用于粗略的频率估计。为了进行更精确的分析,建议使用 莫库相位计.
图 19 以红色显示相位输出。由于 FFT 分析窗口在采集周期内的变化,相位看起来不稳定。此示例仅用于功能演示,并不构成完整的频谱分析仪,因为它缺少窗口函数和超外差模块等必要组件。
图 18:FFT_1024 IP 核的多仪器模式测试配置和幅度输出结果。将 10 MHz 正弦波施加到 Moku Cloud Compile 的输入 A,并由 FFT_1024 模块进行处理。生成的幅度谱显示在通道 A(红色)上,显示出两个峰值,分别对应于输入信号的正负频率分量。
图 19:多仪器模式测试配置和 FFT_1024 IP 核的相位响应。由于 FFT 分析窗口相对于输入信号的随机时间偏移,观察到的相位响应似乎不稳定。
8. FFT_65536
FFT_65536 是 FFT_1024 的一个变体,使用相同的 IP 核编译器生成,但配置了更多的 FFT 点数。虽然两个核共享相同的基础,但 FFT_65536 具有不同的配置参数和输出数据格式,以适应增加的点数。表 11 提供了详细的端口规格和更新的信号连接,并突出显示了更改之处。
由于硬件资源限制,FFT_65536 IP 核在 Moku:Go 或 Moku:Lab 上不受支持,必须部署在 Moku:Pro 上。
表11:FFT_65536 IP核的端口定义。与FFT_1024不同的参数以粗体显示。
| 名称 | 方向性 | 描述 |
| 时钟 | 输入 | 上升沿时钟。 |
| 阿雷森 | 输入 | 低电平有效同步清零(可选,始终优先于 aclken)。至少需要两个周期的 aresetn 有效脉冲。 |
| s_axis_config_tdata[39:0] | 输入 | tdata 为配置通道。第 0 位控制正向或反向 FFT。[32:1] 为输出的比例。其他位为空。 |
| s_axis_config_tvalid | 输入 | tvalid 用于配置通道。 |
| s_axis_config_tready | 输出 | 准备好配置频道。 |
| s_axis_data_tdata[31:0] | 输入 | tdata 为数据输入通道。承载未处理的样本数据:实部 [15:0] 和虚部 [31:16]。 |
| s_axis_data_tvalid | 输入 | 数据输入通道的tvalid。设置为恒定高电平。 |
| s_axis_data_tready | 输出 | tready 表示数据输入通道。内核使用它来表示已准备好接收数据。 |
| s_axis_data_tlast | 输入 | tlast 为数据输入通道。由外部主机在帧的最后一个样本处置位。 |
| m_axis_data_tdata[31:0] | 输出 | tdata 为数据输出通道。承载处理后的样本数据实部 [15:0] 和虚部 [31:16]。信号格式为有符号 16 位,包含 15 个小数位。 |
| m_axis_data_tuser[15:0] | 输出 | tuser 表示数据输出通道。包含每个样本信息的索引。 |
| m_axis_data_tvalid | 输出 | tvalid 表示数据输出通道。由内核置位,表示其能够提供样本数据。 |
| m_axis_data_tready | 输入 | tready 表示数据输出通道。由外部模块置位,表示已准备好接受数据。 |
| m_axis_data_tlast | 输出 | tlast 为数据输出通道。由内核在帧的最后一个样本处置位。 |
| 事件框架已启动 | 输出 | 当核心开始处理新帧时断言。 |
| event_tlast_unexpected | 输出 | 当核心在非帧中最后一个数据样本上看到 s_axis_data_tlast 高时断言。 |
| 事件上次丢失 | 输出 | 当 s_axis_data_tlast 在一帧的最后一个数据样本上为低时断言。 |
| 事件状态通道停止 | 输出 | 当核心尝试将数据写入状态通道但无法执行时,发出断言。 |
| 事件数据进入通道暂停 | 输出 | 当核心从数据输入通道请求数据但没有可用数据时,发出断言。 |
| 事件数据输出通道停止 | 输出 | 当核心尝试将数据写入数据输出通道但无法执行时,发出断言。 |
代码 65536 中展示了实例化 FFT_16 和一个 Cordic_Translate_8 的 VHDL 示例。Moku Cloud Compile 的输出包括 InputA 的幅度和相位谱,以及频率索引。此外,Control0 用于设置比例参数,Control1 的 LSB 决定 FFT 方向。
代码 8:VHDL 示例,演示一个 FFT_65536 和一个 Cordic_Translate_16 模块的实例化。
LIBRARY ieee;
ARCHITECTURE Behavioural OF CustomWrapper IS
TYPE array_tuser IS ARRAY (0 TO 19) OF signed(15 DOWNTO 0);
SIGNAL aresetn, aresetn_dly : STD_LOGIC;
SIGNAL s_axis_data_tdata : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL s_axis_data_tready : STD_LOGIC;
SIGNAL m_axis_data_tlast : STD_LOGIC;
SIGNAL m_axis_data_tvalid, m_axis_data_tvalid_dly : STD_LOGIC;
SIGNAL count_out, m_axis_data_tuser : signed(15 DOWNTO 0);
SIGNAL m_axis_data_tuser_dly : array_tuser;
SIGNAL fftdata_temp : signed(31 DOWNTO 0);
SIGNAL real, im : signed(15 DOWNTO 0);
SIGNAL m_axis_dout_tvalid : STD_LOGIC;
SIGNAL tdata_temp : signed(31 DOWNTO 0);
BEGIN
FFT_DUT : FFT_65536
PORT MAP(
aclk => clk,
-- aresetn => (not Reset) and FFT_reset and FFT_reset_dly,
aresetn => (NOT reset) AND aresetn AND aresetn_dly,
-- Control FFT direction with LSB of Control1
-- and scale of the FFT output with Control0
s_axis_config_tdata => "0000000" & Control0(31 DOWNTO 0) & Control1(0),
-- Config data is always valid
s_axis_config_tvalid => '1',
-- Leave config ready signal open
-- config data is constant
s_axis_config_tready => OPEN,
-- Input only has real values
s_axis_data_tdata => s_axis_data_tdata,
-- Input data is always valid
s_axis_data_tvalid => '1',
-- Data ready logic
s_axis_data_tready => s_axis_data_tready,
-- Continuous data stream
-- don't have last sample
s_axis_data_tlast => '0',
-- Transformed data
m_axis_data_tdata => fftdata_temp,
-- FFT frequency index
m_axis_data_tuser => m_axis_data_tuser,
-- output is valid
m_axis_data_tvalid => m_axis_data_tvalid,
-- Slave device is always ready to accept output
m_axis_data_tready => '1',
-- last sample of the frame
m_axis_data_tlast => m_axis_data_tlast,
-- don't care events
event_frame_started => OPEN,
event_tlast_unexpected => OPEN,
event_tlast_missing => OPEN,
event_status_channel_halt => OPEN,
event_data_in_channel_halt => OPEN,
event_data_out_channel_halt => OPEN
);
-- only output data when data is valid
PROCESS (clk)
BEGIN
IF rising_edge(clk) THEN
IF s_axis_data_tready THEN
s_axis_data_tdata <= x"0000" & STD_LOGIC_VECTOR(InputA);
END IF;
IF m_axis_data_tvalid THEN
-- real part
real <= fftdata_temp(15 DOWNTO 0);
-- imaginary part
im <= fftdata_temp(31 DOWNTO 16);
END IF;
-- delay 20 clk cycles
m_axis_data_tuser_dly <= m_axis_data_tuser & m_axis_data_tuser_dly(0 TO 18);
END IF;
END PROCESS;
-- reset process
-- reset fft when the tlast is high
PROCESS (clk)
BEGIN
IF rising_edge(Clk) THEN
aresetn_dly <= aresetn;
IF m_axis_data_tlast THEN
aresetn <= '0';
ELSE
aresetn <= '1'; END IF; END IF; END PROCESS; Cordic : Cordic_Translate_16 PORT MAP( aclk => clk,
s_axis_cartesian_tvalid => m_axis_data_tvalid,
s_axis_cartesian_tdata => STD_LOGIC_VECTOR(im & real),
m_axis_dout_tvalid => m_axis_dout_tvalid,
m_axis_dout_tdata => tdata_temp
);
PROCESS (clk)
BEGIN
IF rising_edge(clk) THEN
IF m_axis_dout_tvalid THEN
OutputA <= signed(tdata_temp(15 DOWNTO 0));
OutputB <= signed(tdata_temp(31 DOWNTO 16));
OutputC <= signed(m_axis_data_tuser_dly(19));
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
Moku:Pro 多仪器模式测试配置如图 20 所示。被测信号由 Moku 示波器内置的波形发生器生成,并通过内部数字信号总线路由回 Moku Cloud Compile 输入。Moku Cloud Compile 产生三个输出:OutputA 和 OutputB 代表转换后的幅度和相位,OutputC 代表频率指标。这些输出连接到示波器的输入端进行监控。

图 20:Moku:Pro FFT_65536 测试多仪器模式配置。
FFT_65536 的输出幅度和频率索引如图 21 所示。Control0 经过微调以防止信号溢出,Control1 设置为 1 以执行正向 FFT。值得注意的是,由于 16 点 FFT 使用带符号的 65,536 位表示法,频率索引似乎发生了符号翻转,从而导致溢出。然而,这种溢出是无害的,因为它有效地区分了正负频率。幅度通道在 80 MHz 频率索引附近出现峰值,这对应于 Moku Cloud Compile 的 80 MHz 输入信号(假设 Moku:Pro Moku Cloud Compile 的时钟频率为 312.5 MHz)。
![]()
\(文本{频率} = frac{53.86 mu 文本{s}}{104.95 mu 文本{s}} 乘以 frac{312.5 文本{MHz}}{2} = 80.19 文本{MHz}\)
图21:实例化的FFT_65536的测试结果及其相应的幅度谱输出。
定制IP核
Moku Cloud Compile 还允许用户上传自定义 .xci 文件,这些文件定义了 Vivado 中生成的 IP 核的配置。Moku Cloud Compile 能够解析这些 .xci 文件,在后端加载相应的 IP 核,并在用户设计中实现它们的实例化。
需要注意的是,.xci 文件必须使用 Vivado 2022.2 版本生成,以确保与 Moku Cloud Compile 后端兼容。Vivado 2022.2 支持的所有 IP 核也同样受 Moku Cloud Compile 支持。Vivado 2022.2 可从以下网址下载: AMD 官方网站. 下面的部分通过一个例子来说明这个过程。
1.创建Vivado项目:
在项目创建过程中,选择正确的硬件平台至关重要。在设置过程中,必须指定目标 FPGA 器件。表 12 列出了三种受支持的硬件平台的 FPGA 平台模型,图 22 展示了一个示例配置。
表 12:Moku 平台的 FPGA 型号。
| 平台 | FPGA模型 |
| Moku:Go | xc7z020clg400-1 |
| Moku:Lab | xc7z020clg484-3 |
| Moku:Pro | xczu9egffvc900-2 |

图 22:必须在 Vivado 中使用适当的 FPGA 平台设置创建项目。本例中选择 Moku:Go 平台作为目标设备。
2. 构建 IP 核并找到 .xci 文件
按照图 23 所示的步骤可以编译自定义 IP 核。首先,选择 IP目录 来自 项目管理员 在左侧面板上配置 IP 核(步骤 1)。然后,从右侧面板的列表中选择所需的 IP 核(步骤 2)。配置过程中可能需要时钟频率;表 13 提供了特定于平台的时钟速率。配置 IP 核后,它将出现在 来源 窗口(步骤 3)。生成的 .xci 文件的位置可以在 源文件属性 面板(步骤 4)。
表 13:Moku Cloud Compile 在不同硬件平台上的时钟频率。
| 平台 | Moku Cloud 编译时钟频率 (MHz) |
| Moku:Go | 31.25 |
| Moku:Lab | 125 |
| Moku:Pro |
312.5 |

图23:配置IP核的流程。
3.上传.xci文件到Moku云编译并修改OUTPUTDIR
IP 核编译完成后,应将 .xci 文件上传到 Moku Cloud Compile 网页界面。为了确保在 Moku Cloud Compile 后端成功重新编译, 输出目录 参数必须设置为“../output”。图 24 展示了此过程的一个示例。

图24:将.xci 文件上传到 Moku Cloud Compile,并将 OUTPUTDIR 设置为“../output”,以确保正确编译。
4. 在 Moku Cloud Compile 中实例化 IP 核并构建设计
要在 Moku Cloud Compile 中实例化自定义 IP 核,必须了解端口配置和信号连接。图 25 展示了查找实例化模板的过程。首先选择“IP 源”,然后找到 .vho 和 .veo 文件,这两个文件提供了示例实例。.vho 文件适用于 VHDL,而 .veo 文件适用于 Verilog。

图 25:定位 IP 核实例化模板。
接下来,使用模板实例化自定义 IP 核的过程如图 26 所示。这样就完成了设置,之后可以在 Moku Cloud Compile 中编译自定义 IP 核并生成比特流。

图26:在Moku Cloud Compile中实例化IP核,并将其信号连接到CustomWrapper模块的相应端口。
Verilog 支持
Verilog 与 VHDL 类似,是一种硬件描述语言,但它通常更紧凑,并且与硬件建模紧密相关。与 VHDL 中用户通常仅定义 CustomWrapper 实体的行为架构不同,Verilog 需要整个 CustomWrapper 模块的声明和结构定义。这包括明确指定 CustomWrapper 端口和内部逻辑。
本节提供了使用 Verilog 实例化 AddSubtract_16 IP 核的示例,如代码 9 所示。需要注意的是,Verilog 区分大小写。因此,正确的大写和一致的命名对于避免合成或行为错误至关重要。
代码 9:示例 Verilog 实现,演示对 AddSubtract_16 IP 核的支持。
module CustomWrapper (
input wire Clk,
input wire Reset,
input wire [31:0] Sync,
// 4 input ports
input wire signed [15:0] InputA,
input wire signed [15:0] InputB,
input wire signed [15:0] InputC,
input wire signed [15:0] InputD,
// external trigger input port
input wire ExtTrig,
// 4 output ports
output wire signed [15:0] OutputA,
output wire signed [15:0] OutputB,
output wire signed [15:0] OutputC,
output wire signed [15:0] OutputD,
// enable/disable interpolation
output wire OutputInterpA,
output wire OutputInterpB,
output wire OutputInterpC,
output wire OutputInterpD,
// 16 control registers
input wire [31:0] Control0,
input wire [31:0] Control1,
input wire [31:0] Control2,
input wire [31:0] Control3,
input wire [31:0] Control4,
input wire [31:0] Control5,
input wire [31:0] Control6,
input wire [31:0] Control7,
input wire [31:0] Control8,
input wire [31:0] Control9,
input wire [31:0] Control10,
input wire [31:0] Control11,
input wire [31:0] Control12,
input wire [31:0] Control13,
input wire [31:0] Control14,
input wire [31:0] Control15
);
AddSubtract_16 AddSubtract_DUT (
.A(InputA), // input wire [15 : 0] A
.B(InputB), // input wire [15 : 0] B
.CLK(Clk), // input wire CLK
.ADD(Control0[0]), // input wire ADD
.CE(1'b1), // input wire CE
.S(OutputA) // output wire [15 : 0] S
);
endmodule
将示例Verilog代码上传至Moku Cloud Compile后,AddSubtract_16模块可以成功编译,并生成相应的比特流,如图27所示。 
图 27:Moku Cloud Compile 界面用于编译 AddSubtract_16 模块并从 Verilog 代码生成比特流。
结语
Moku Cloud Compile 提供八个预编译 IP 核,用于执行信号处理任务,例如算术运算、滤波、波形生成和频谱分析。上文已详细描述了每个 IP 核,并提供了详细的端口定义、VHDL 实现示例以及在 Moku 硬件平台上使用多仪器模式的测试配置。
除了内置核之外,用户还可以通过导入 Vivado 2022.2 生成的 .xci 文件来上传自定义 IP 核。Moku Cloud Compile 还支持 Verilog 和 VHDL 语言。这些功能共同增强了 Moku Cloud Compile 的功能,使其成为一个强大而灵活的平台,可用于快速开发和部署基于 FPGA 的数字信号处理解决方案。