5 进行修改

5.1 与定制逻辑的集成

Xillinux 发行版已配置为便于与应用逻辑集成。连接数据源和数据接收端的前端接口是 xillydemo.v 或 xillydemo.vhd 文件(取决于所选语 言)。若仅将 Xillybus IP 核用作 Linux 主机与逻辑结构之间的数据传输通道,则启动分区套件中的其他 HDL 文件均可忽略。

可将包含定制逻辑设计的其他 HDL 文件添加到第 3.3 节所述的工程中,然后以与 最初相同的方式重新构建。要使用更新后的逻辑启动系统,请将新的 xillydemo.bit 复制到(Micro)SD 卡的启动分区中,覆盖原有文件。请 注意,也可以使用 Zynq 开发板本身将 xillydemo.bit 复制到启动分区,如第 3.5 节所示。

无需重复初始发行版部署的其他步骤,因此逻辑开发周期相当快捷简单。

不支持通过 JTAG 对 PL 部分进行编程。

当将 Xillybus IP 核连接到定制应用逻辑时,强烈建议仅通过 FIFO 与 Xillybus IP 核交互,并且至少在第一阶段不要尝试用逻 辑来模拟 FIFO 的行为。

一个例外情况是将 Xillybus 连接到块 RAM(block RAM)或寄存器时,此时应遵循 xillydemo 模块中所示的方法。

在 xillydemo 模块中,FIFO 用于执行将从主机到达的数据回环送回主机的操作。两个 FIFO 的端口都连接到 Xillybus IP 核, 使该核充当自身的数据源和数据接收端。

在更实用的场景中,仅将 FIFO 的一端连接到 Xillybus IP 核,另一端连接到应用数据源或数据接收端。

xillydemo 模块中使用的 FIFO 仅支持两侧共用同一时钟,因为两侧都由 Xillybus 的主时钟驱动。在实际应用中,可能需要将其替换为读 写侧具有独立时钟的 FIFO,从而允许数据源和数据接收端使用总线时钟以外的时钟。这样,FIFO 不仅充当中介,还用于正确的时钟域跨越 (clock domain crossing)。

请注意,对于从 FPGA 到主机的数据流,Xillybus IP 核期望使用 普通 FIFO(区别于首字透传 FIFO,即 First Word Fall Through)。

与集成定制逻辑相关的文档如下:

5.2 使用其他开发板

在尝试于 Z-Turn Lite、Zedboard、MicroZed 或 Zybo 之外的其他开发板上运行 Xillinux 之前,可能需要进行某些修 改。

但不建议尝试将 Xillinux 移植到其他硬件,因为该过程较为困难。经验表明,如果移植 Xillinux 的目的不是为了使用 Xillybus IP 核,那么从头开始反而更容易。

以下是需要注意的部分事项清单。

  • 购买的开发板应提供 XML 文件作为参考(用作 ps7_system_prj.xml)。该文件包含处理器设置,包括 MIO 引脚的实际使用 情况和 DDR 引脚的电气参数。建议采用参考文件,至少作为起点。

  • 如果采用 XML 文件作为参考,则无论参考文件中如何设定,FPGA CLK1(FCLK_CLK1)都必须设置为 100 MHz。

  • 如果手动进行更改,则需注意处理器内核的 MIO 分配:ARM 内核有 54 个 I/O 引脚,这些引脚以固定布局连接到芯片的物理 引脚。在工程的块设计中,ARM 内核配置为将这些引脚分配特定角色(例如 USB 接口、以太网等),这些角色必须与开发板上这些引脚的 连线相匹配。

  • 如果更改了处理器配置(即在 XML 文件中更改),则必须基于新的 XML 文件重新生成 FSBL(第一阶段启动加载程序)以 及 U-boot 二进制文件,从而重建 boot.bin。在 Vivado 块设计工具中所做的更改,通过 FSBL 中的初始化例程生效。该例程向 ARM 处理器中 的寄存器写入值,这些值反映了在 Vivado 中所做的设置,并导出到 SDK。请注意,Vivado 工程中处理器的参数可能不准确,因此应基于套 件中提供的 XPS 工程来生成 FSBL。要设置 U-boot 的源码,请参考 /usr/src/xillinux/uboot-patches/ 中的 README 文件。

  • 或者,在某些情况下,可以通过“poke”功能精确定位寄存器设置的更改,从而避免重建 boot.bin。见第 5.6 节。

  • 可能还需要对 devicetree.dtb 进行更改,以反映新设置。现有 DTB 的源文件(DTS 格式)可在 Linux 内核源码中找到(见第 6.2 节)。

  • 需要将 VGA/DVI 输出(如果适用)匹配到目标开发板。这通过编辑 src/ 子目录下的 xillybus.v 文件来完成。请注意,来自 “system” 模块的信号宽度为 8 位,截断为 4 位的操作在 xillybus.v 中执行。因此,将这些信号连接到任何 VGA/DVI 编码器芯片都相当容 易。

5.3 更改系统中的时钟频率

ARM 处理器的内核提供四个供逻辑结构使用的时钟,通常称为 FCLK_CLKn。需要注意的是,它们的频率由 FSBL(第一阶段启动加载 程序)在加载 U-boot 之前设置。

因此,尽管在 Vivado 中设置了时钟频率,但这些频率仅对传播时序约束以及在 SDK 上编译的裸机应用程序的初始化有 效。

如果硬件应用需要不同的频率,建议执行以下一系列操作:

  • 在 Vivado 中更新时钟的频率。

  • 重新生成网表(这对于更新 .ncf 文件中的时序约束是必要的)。

  • 将工程导出到 SDK,并基于此创建一个 FSBL 应用程序工程。

  • 从 Vivado 的报告中了解所需设置对应的寄存器值。

  • 根据需要,利用 “poke” 功能进行调整,如第 5.6 节所述。

有关每个步骤(最后一步除外)的详细操作,请参考 AMD 的指南。

5.4 将 GPIO I/O 引脚用于 PL 逻 辑

5.4.1 Z-Turn Lite

虽然 Z-Turn Lite 开发板本身并未提供方便实验室使用的 I/O 引脚接口,但将其连接到 Z-Turn Lite IO Cape 扩展板后,除了 HDMI 接口外,还可通过标准连接器提供 68 个 I/O 引脚和一个按键。

这 68 个引脚全部连接到两个 40 针连接器 J3 和 J8 上,可连接标准扁平排线。IO Cape 板还有一些额外的连接器,它们与 J3 和 J8 共享引脚。由于所有额外连接器的引脚都可在 J3 和 J8 上获得,Xillydemo 顶层模块中这些引脚的端口被定义为名为 J3 和 J8 的向 量,并带有引脚约束将其路由到对应的连接器。

在 Verilog / VHDL 中,J3 和 J8 的端口向量对应于连接器引脚号减 3:Verilog / VHDL 中的信号 J3[0] 对应物理引脚 J3/3,J3[1] 对应 J3/4,依此类推,J3[33] 对应 J3/36。J8 同理。

为简便起见,xillydemo.v 和 xillydemo.vhd 中将属于 J8 的所有引脚连接到处理器的 GPIO 引脚,从而可直接由处理器上运行 的软件控制。J3 的所有引脚在 xillydemo.v 和 xillydemo.vhd 中被驱动为低电平,用户可通过修改相应的 xillydemo 模块文件轻松将其用于应 用逻辑。

这种将引脚分配给 GPIO 和应用逻辑的划分方式也很容易通过修改 xillydemo 模块中的连接来改变。如果用作 GPIO 的引脚 数量发生变化,则应相应更改 xillybus 模块的 gpio_width 实例化参数(generic)。当前值为 35,对应 J8 连接器的 34 个 I/O 引脚,再加上 Cape 板按键的 1 个 GPIO。

如前所述,开发板上还有其他连接器与 J3 和 J8 共享引脚,这些引脚仍然可以使用。但这需要查阅 Cape 板的原理图以确定 各引脚的对应关系。

这种引脚共享的一个副作用是,某些用作备用连接器 I2C 的引脚在 Cape 板上带有上拉电 阻:J3[19]、J3[18]、J8[28] 和 J8[31](使用 Verilog / VHDL 向量信号表示法)。由于这些上拉电阻位于板卡上,因此即使使用 J3 和 J8 连接 器上的这些引脚,上拉电阻仍然有效。

HDMI 连接器是独立的,不与 J3、J8 或任何其他连接器共享引脚。

5.4.2 Zedboard 和 Zybo

在 Zedboard 和 Zybo 开发板上,许多物理 I/O 引脚连接到 ARM 处理器的 GPIO 端口(PS),从而可以直接从 Linux 控制和 监视这些引脚。但通常也希望将这些物理引脚连接到 FPGA 逻辑(即 PL)上。

将 Zynq 的 PL 引脚用于 I/O 的技术与任何 AMD FPGA 完全相同:信号在顶层模块(xillydemo.v 或 xillydemo.vhd)中作为 输入、输出或双向端口引出。将这些信号分配到物理引脚的操作在 xillydemo.xdc 中完成。

由于引脚用作 GPIO 信号,它们将从处理器中移出并交给 PL 部分。 例如,XDC 文件中的以下行:

set_property -dict "PACKAGE_PIN U5 IOSTANDARD LVCMOS33" [get_ports "PS_GPIO[55]"]

可替换为:

set_property -dict "PACKAGE_PIN U5 IOSTANDARD LVCMOS33" [get_ports "my_output"]

如果希望 my_output 出现在引脚 U5 上。

但进行此替换后,PS_GPIO[55] 将缺少引脚分配。尽管 AMD 的工具可能会在实现过程中自动为该端口分配位置,但建议为 所有被替换的 PS_GPIO 分配一个 I/O 引脚。另一种选择是消除该信号,如下所述。

因此,对于这些被替换的 PS_GPIO 信号,有两种解决方案:

  • 简单方法:在器件上找到未使用的引脚,并将这些引脚分配给被替换的 PS_GPIO 信号。尽管这并非十分干净的解决方案 (GPIO 引脚连接到板卡上任意位置),但实际无害,因为 GPIO 默认是输入。除非软件意外驱动 GPIO(可能性不大),否则这些引脚上的 电气状态保持不变。例如,在 Zedboard 上,FMC 连接器通常提供许多未使用的引脚。

  • 较难的方法:减少 PS_GPIO 引脚的数量。这在 Zybo 上可能是必需的,因为 Zybo 没有太多空闲引脚。

下面讨论第二种解决方案。例如,假设为了用 PL 的信号替换其引脚,我们从 XDC 文件中移除了 PS_GPIO[55:48]。请注 意,如果需要使用较低索引的 PS_GPIO 引脚,则应将被替换的 PS_GPIO 信号接管最高索引的引脚,然后消除后者。我们无法消除某个特定 范围的 PS_GPIO 索引,只能减少最大索引。

应减少 xillydemo.v/vhd 中 PS_GPIO 的宽度,以反映在 XDC 文件中仍有引脚分配的那些。

但这还不够。在此状态下尝试构建工程时,这些引脚会发出严重警告(可能声称存在多驱动、高阻和接地问题)。

要解决此问题,请编辑 vivado-essentials/system.v 的以下部分:

generate
  for (i=0; i<56; i=i+1)
    begin: gpio
       assign gpio_tri_i[i] = processing_system7_0_GPIO[i];
       assign processing_system7_0_GPIO[i] = gpio_tri_t[i] ? 1'bz :
                                             gpio_tri_o[i];
    end
endgenerate

将索引范围(即 i<56 部分)减少为实际使用的 GPIO 数量(示例中为 48)。

根据 Vivado 版本的不同,可能还需要调整信号的宽度。

如果需要在块设计(block design)中修正 GPIO 宽度:在 Vivado 主窗口中,点击左侧的 “Open Block Design”。右键点击 处理器模块(processing_system_7_0,带有 ZYNQ 标记),选择 “Customize block”。在左侧选择 “MIO Configuration”,展开 “I/O Peripherals” 层级,并展开 GPIO 层级(位于底部)。当前 EMIO GPIO (Width) 参数为 56,即 GPIO 引脚数。将其减少到所需数量(本例中 为 48)。

5.5 使用 7020 MicroZed

适用于 MicroZed 的启动分区套件默认面向 7010 MicroZed 开发板。但通过对用于创建 Vivado 工程的 xillydemo-vivado.tcl 文件(即套件中的 verilog/xillydemo-vivado.tcl 或 vhdl/xillydemo-vivado.tcl,取决于所选语言)进行小幅修改,也可在 7020 MicroZed 上使用 Vivado 工作。

解压套件后(并在 Vivado 中使用之前),应编辑该文件,将其中的:

set thepart "xc7z010clg400-1"

(大约第 11 行)改为:

set thepart "xc7z020clg400-1"

其余构建过程完全相同。

5.6 启动前操作硬件寄存器 (“poke”)

通常希望在无需重建 boot.bin 文件的情况下对 ARM 处理器的硬件设置进行微小更改(第 5.3 节讨论了典型的重建流 程)。

例如,处理器 MIO/EMIO 配置的微小变动会导致寄存器设置的少数几处更改,这些更改可通过比较系统设置导出到软件工具 时生成的报告来轻松推断。

处理器硬件寄存器在 AMD 的 Zynq-7000 AP SoC 技术参考手册(也称为 TRM 或 ug585)中有详细说明。

要操作寄存器,需在内核的设备树中添加一个条目(通常通过编辑 Linux 内核源码中给定的相应 DTS 文件,见第 6.2 节)。

如下例所示的条目可添加在设备树层次结构的任何位置(最好放在 “chosen” 条目之后):

poke {
    compatible = "xillybus,poke-1.0";
    sequence = < 0 0xf8002000 0
           0 0xf800200c 0
           0 0xf8002018 0
           1 0xf800200c 0x20
           0 0xf8002018 0
           0 0xf8002018 0
           1 0xf800200c 0x21
           0 0xf8002018 0
           0 0xf8002018 0
          >;
};

应修改 “sequence” 部分以设置所需的寄存器读/写序列。每个操作由 “sequence” 数组中的三个值定义。三元组(即操作)的 数量没有限制。上面 “sequence” 条目的格式(使用制表符和每行三个值)不具有语法意义——重要的是每个三元组代表一个操作,具体如 下:

  • 第一个元素:读或写。值为 0 表示读,否则表示写。

  • 第二个元素:地址。必须 32 位对齐(地址的低 2 位必须为零)。

  • 第三个元素:要写入的值。对于读操作,该值被忽略。

操作按照设备树条目中列出的顺序执行,每次操作之间具有不可预测的延迟。

在上面的示例中(该示例没有实际意义),操作的是处理器 ttc2(三路定时器计数器 2)的寄存器:前三个操作为了演示而 读取寄存器。然后短暂启用计数器,读取其计数值两次以显示其变化,然后禁用计数器。之后再次读取计数值两次,以显示其已停止。

这些操作的结果可在内核的消息日志中找到,该日志可在串行控制台(UART)和/或 shell 提示符下的 dmesg 命令中查 看:

[ 0.000000] poke read addr=f8002000: value=00000000
[ 0.000000] poke read addr=f800200c: value=00000021
[ 0.000000] poke read addr=f8002018: value=00000000
[ 0.000000] poke write addr=f800200c: value=00000020
[ 0.000000] poke read addr=f8002018: value=00000009
[ 0.000000] poke read addr=f8002018: value=00004f68
[ 0.000000] poke write addr=f800200c: value=00000021
[ 0.000000] poke read addr=f8002018: value=000013ec
[ 0.000000] poke read addr=f8002018: value=000013ec

从 0xf8002018 读取的值当然会变化,因为它们来自一个运行的计数器。

寄存器修改在内核启动过程的早期进行,在任何设备驱动程序加载之前。但请注意,U-boot 在 Linux 启动之前就已经设置了 ARM 处理器的部分硬件外设,因此它们已经处于活动状态。还需注意,修改与 ARM 处理器基本功能(例如时钟和中断)相关的寄存器可能 破坏处理器本身的正常功能。即使在内核执行 “poke” 时中断已被禁用,这种情况仍可能发生。

尝试访问被内核内存管理和/或硬件本身禁止的地址,将导致内核 Oops、内核 panic,甚至可能完全死机。后两种情况会导 致启动失败。出现 “imprecise external abort (0x406)” 的内核 panic 很可能是由于尝试访问硬件上不合法的地址所致。

此外,由于早期内核控制台消息在生成时存储在内部内存缓冲区中,并在稍后阶段(串行端口设置完成后)才写入控制台, 因此早期的死机可能导致控制台完全没有输出——在 U-boot 的 “done, booting the kernel” 消息之后没有任何内容出现。

因此,当控制台上没有内核消息时,并不一定意味着内核没有启动。这可能是由于在将存储于内存中的内核消息写入控制台 之前系统已死机所致。原因可能是对寄存器的非法修改。

“poke” 功能是通过专门为 Xillinux-2.0 内核打补丁而添加的,不属于主线 Linux 内核的一部分。