3 信号描述
3.1 FPGA 信号的命名约定
除了两个全局信号 bus_clk 和 quiesce 之外,所有信号都遵循一个简单的约定。例如,写使能信号可能命名为 user_w_write_32_wren。该名称分为四个部分:
-
“user” 前缀:所有用户接口信号共有。
-
“w” 部分:指示该信号属于从主机到 FPGA 的流(主机“写入”)。从 FPGA 到主机的流则使用 “r”。地址信号没有此部分,因为它们适用于 两个方向。 注意,选择 “w” 或 “r” 是从主机的视角出发。
-
“write_32” 字符串出现在相关设备文件的名称中: 通常是 /dev/xillybus_write_32 或 /dev/xillyusb_00_write_32,具体取决于 情况。
-
后缀表示信号的含义。
在本节的其余部分中,设备文件名(第三部分)用 {devfile} 表示,以免混淆。
每个信号名称后跟有 (IN) 表示该信号是 IP 核的输入,或 (OUT) 表示是 IP 核的输出。
3.2 主机到 FPGA 传输的信号
-
user_w_{devfile}_data (OUT) —— 该信号在写周期内包含数据。
-
user_w_{devfile}_wren (OUT) —— 该信号是 FIFO 的写使能信号: 当 user_w_{devfile}_data 信号上存在有效数据 且应写入 FIFO(或任何模拟 FIFO 行为的逻辑)时,该信号为高电平。
-
user_w_{devfile}_full (IN) —— 该信号告知 IP 核无法再写入更多数据。
重要: ’full’(满)信号只能在写周期之后的时钟周期内从低电平变为高电平。 所有标准 FIFO 的行为都是如此,因此该规则仅当 IP 核直接与应用逻辑连接(即中间没有 FIFO)时才相关。
此规则的原因是 Xillybus IP 核将低电平的 ’full’(满)信号视为可以开始从主机传输数据的绿灯。若不遵守此规则,可能会导 致忽略 ’full’(满)条件的零星写入。
典型的 Verilog 实现 ’full’ 信号的代码应类似于:
always @(posedge bus_clk) if (ready_to_get_more_data) user_w_mydevice_full <= 0; // Turn low any time else if (user_w_mydevice_wren && { ... some condition ... } ) user_w_mydevice_full <= 1; // Only in conjunction with wrenVHDL 代码同理:
process (bus_clk) begin if (bus_clk'event and bus_clk = '1') then if (ready_to_get_more_data = '1') then user_w_mydevice_full <= '0'; -- Turn low any time elsif (user_w_mydevice_wren = '1' and {some condition} ) then user_w_mydevice_full <= '1'; -- Turn high only with wren end if; end if; end process; -
user_w_{devfile}_open (OUT) —— 当主机上相关的设备文件以写入方式打开时(如果允许以只读方式打开,则不会改变此信 号),此信号为高电平。此信号可用于在文件关闭时复位 FIFO 或其他逻辑(用作低电平有效复位)。
如果文件被主机上的多个进程打开(例如由于调用 fork() 函数),此信号将保持高电平,直到所有进程都关闭了该文 件。
3.3 FPGA 到主机传输的信号
-
user_r_{devfile}_data (IN) —— 该信号在读周期内包含数据。该信号仅允许在 FIFO 会改变其值时改变。换言之,它只能在 user_r_{devfile}_rden 为高电平之后的时钟周期改变。
-
user_r_{devfile}_rden (OUT) —— 该信号是 FIFO 的读使能信号: 当此信号为高电平时,user_r_{devfile}_data 必 须在下一个时钟周期包含有效数据。
-
user_r_{devfile}_empty (IN) —— 该信号告知 IP 核无法再读取更多数据。
重要: ’empty’(空)信号只能在读周期之后的时钟周期内从低电平变为高电平。 所有标 准 FIFO 的行为都是如此,因此该规则仅当 IP 核直接与应用逻辑连接(即中间没有 FIFO)时才相关。
此规则的原因是 Xillybus IP 核将低电平的 ’empty’(空)信号视为可以开始向主机传输数据的绿灯。若不遵守此规则,可能 会导致忽略 FIFO 为空的零星读取。
典型的 Verilog 实现 ’empty’ 信号的代码应类似于:
always @(posedge bus_clk) if (ready_to_give_more_data) user_r_mydevice_empty <= 0; // Turn low any time else if (user_r_mydevice_rden && { ... some condition ... } ) user_r_mydevice_empty <= 1; // Turn high only with rdenVHDL 代码同理:
process (bus_clk) begin if (bus_clk'event and bus_clk = '1') then if (ready_to_give_more_data = '1') then user_r_mydevice_empty <= '0'; -- Turn low any time elsif (user_r_mydevice_rden = '1' and {some condition} ) then user_r_mydevice_empty <= '1'; -- Turn high only with rden end if; end if; end process; -
user_r_{devfile}_eof (IN) —— 该信号告知 IP 核生成文件结束符(EOF)。’eof’ 为高电平的结果还包括,IP 核将不再从 FIFO 读取数据(即 user_r_{devfile}_rden 保持低电平,直到文件关闭后重新打开)。
在主机端,应用软件将先读完此信号变为高电平之前 IP 核已接收的所有数据,然后当调用 read() 函数时才会接收到 EOF。
请注意,如果还有未被应用软件读取的数据,’eof’ 信号不会立即在主机端产生 EOF。在主机端传递 EOF 是符合常理的,即 在主机读取完所有数据之后。
’EOF’ 信号变为高电平后,它保持高电平还是变为低电平都无关紧要。IP 核会记住 EOF 请求,直到文件关闭。对于 ’empty’(空)信号, 如果它与 ’eof’ 同时变为高电平,也没有关系。实际上,从 ’eof’ 变为高电平的那一刻起,’empty’(空)信号就完全无关紧要了,直到文件关 闭。
与 ’empty’(空)信号类似,’eof’ 信号仅允许在读周期之后的时钟周期内变为高电平。但有一个例外: 当 ’empty’(空)信号已经为高电平时,’eof’ 可以随时变为高电平。这个例外可用于立即终止主机上的 read() 函数调用(如果该函数在等待数据 时处于休眠状态)。
在不遵守此规则的情况下将 ’eof’ 变为高电平也会生成 EOF,但可能无法准确工作: EOF 之前可能会丢失一些数据,或者在 EOF 之前甚至之后可能会添加不相关的数据(这样应用软件会在 EOF 之后收到数据,这是不合法的)。
确保 ’eof’ 遵守此规则的一种方法是,将 ’eof’ 定义为组合逻辑函数的输出。在 Verilog 中可以这样写:
assign user_r_mydevice_eof = user_r_mydevice_empty && [ ... ];
或在 VHDL 中:
user_r_mydevice_eof <= user_r_mydevice_empty and [ ... ];
采用这种方法,当 ’empty’(空)为低电平时,’eof’ 信号始终为低电平。
-
user_r_{devfile}_open (OUT) —— 当主机上相关的设备文件以读取方式打开时(如果允许以只写方式打开,则不会改变此信 号),此信号为高电平。此信号可用于在文件关闭时复位 FIFO 或其他逻辑(用作低电平有效复位)。
如果文件被主机上的多个进程打开(例如由于调用 fork() 函数),此信号将保持高电平,直到所有进程都关闭了该文 件。
’eof’ 信号与 ’open’ 信号之间没有直接联系。无论 ’eof’ 如何,’open’ 信号都会在主机上关闭文件时变为低电平。但请注意,应用软件通常 会在响应 EOF 时关闭文件。因此很容易错误地认为这两个信号之间存在联系。
3.4 存储器接口信号
Xillybus 设备文件可以配置为具有地址信号。应用软件通过使用标准的文件定位 API(例如 lseek())来为该信号赋值。此外,地址在 FPGA 上会因读周期和写周期而自动递增。
标准 Block RAM 很容易与 IP 核连接。只需使用上述与 FIFO 相关的信号以及下面详述的信号即可。结果是,Block RAM 的 存储阵列以文件形式提供给主机: 对文件的读写操作会导致对存储阵列的读写操作。主机可以访问单个存储单元或存储阵列的 段: 这取决于读或写操作的长度。
也可以在 FPGA 上实现一个寄存器阵列,其行为类似于 Block RAM。这样,主机就可以轻松访问这些寄存器。
’empty’(空)和 ’full’(满)信号可用于减慢需要等待状态的存储器或出于其他原因需要短暂延迟操作的读写操作。
存储器接口需要两个额外的信号:
-
user_{devfile}_addr (OUT) —— 该信号包含当前时刻的地址。当读使能为高电平时,需要从该地址进行读操作。当写使能为高 电平时,需要对该地址进行写操作。将该信号直接连接到 Block RAM 的地址输入将按预期工作。该信号的宽度可配置,最大为 32 位。
地址的值在最大地址处(取决于地址信号的宽度)进行读或写操作后会回到零。如果对 lseek() 的函数调用值超出范围,则只 有最低有效位被复制到此信号。
-
user_{devfile}_addr_update (OUT) —— 该信号在主机上调用 lseek() 函数时在一个时钟周期内为高电平。’update’ 信号与 ’addr’ 信号具有更新值的时钟周期相同。
请注意,当 user_{devfile}_addr 因正常读取或写入操作而自动递增时,user_{devfile}_addr_update 并 不 会变为高电平。
该信号的目的是让应用逻辑有机会表明由于地址更新而需要时间来准备读取的数据。这是通过将 ’empty’(空)信号变为高电 平来响应该更新来实现的。
为此,’empty’(空)信号可以在读周期之后的一个时钟周期变为高电平这一规则有一个例外: 它也可以在 ’update’ 变为高电平之后的一个时钟周期变为高电平。
因此,以下 Verilog 代码是正确的:
always @(posedge bus_clk) if ( { ... memory is ready ... } ) user_r_mydevice_empty <= 0; else if ((user_mydevice_addr_update) && ( user_mydevice_addr > { ... some limit ...} )) user_r_mydevice_empty <= 1;VHDL 代码同理:
process (bus_clk) begin if (bus_clk'event and bus_clk = '1') then if ( { ... memory is ready ... } ) then user_r_mydevice_empty <= '0'; elsif (user_mydevice_addr_update = '1' and user_mydevice_addr > { ... some limit ...} ) then user_r_mydevice_empty <= '1'; end if; end if; end process;请注意,由于 ’empty’(空)可以随时变为低电平,因此合理的做法是在每次地址更新时将 ’empty’(空)变为高电平(无论 地址如何),然后让逻辑评估是否可以将 ’empty’(空)变回低电平。
’full’(满)信号也可以以类似方式变为高电平,尽管不清楚这样做的用途。
当主机上相关的设备文件关闭时(即 user_w_{devfile}_open 和 user_r_{devfile}_open 均为低电平),地址会被复位,因此 其值变为零。但请注意,这并不被视为地址更新,即 user_{devfile}_addr_update 保持低电平。
3.5 quiesce 信号
当主机期望 IP 核完全处于非活动状态(静止状态)时,quiesce 信号为高电平。这通常发生在以下情况:
-
主机的驱动程序尚未加载或已被卸载。
-
在 Windows 上: 当主机即将进入休眠状态时。
-
对于 XillyUSB: 当设备完全未连接到计算机时。
此信号的目的是用作同步复位,但很可能并不必要: 当 IP 核处于非活动状态(即静止状态)时,所有文件均已 关闭。因此,应用逻辑可以仅依赖 *_open 信号作为复位信号。’quiesce’ 信号可用作更全局形式的复位。
