亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> VHDL

基于 Ready/Valid 握手在块 RAM 中实现 AXI FIFO

初次接触 AXI 接口设计模块时,我对其精简流控方式感到惊讶。不同于依赖 busy/valid、full/valid 或 empty/valid 对的传统协议,AXI 仅用两个信号:ready 和 valid. 最初的挫败感很快变成了着迷。

AXI 将流控直接嵌入握手,省去额外状态线。基本规则虽简单,但映射到 FPGA 硬件时需细致注意。本教程演练一个运行在块 RAM 上的 VHDL AXI FIFO 实现。

AXI 解决延迟一周期问题

两个时钟同步模块交换数据流时,防止过读和过写是常见挑战。核心问题在于每个模块只能在发生后一个时钟周期观测对方输出。

基于 Ready/Valid 握手在块 RAM 中实现 AXI FIFO

上图展示顺序模块写入使用经典 写使能/满 信号方案的 FIFO。写入方置位 wr_en 推数据入 FIFO,FIFO 满时拉高 full。问题在于 full 恰在时钟上升沿置位,写入方同周期无法再响应。解决方案是提供前瞻信号如 almost_empty,给上游逻辑提前量。

Ready/Valid 握手

AXI 流接口用双信号握手解决此时序困境:ready 和 valid。接收方驱动 ready;高电平表示准备好接收新数据。发送方驱动 valid;高电平表示总线上数据稳定可采样。仅当两信号同一上升沿均高时发生传输。

基于 Ready/Valid 握手在块 RAM 中实现 AXI FIFO

波形演示单数据项传输。数据在上升沿采样,同常规同步设计。

实现

用 VHDL 构建 AXI FIFO 有多种方式。移位寄存器虽可行,但环形缓冲区配合块 RAM 最效率且可扩展。下面呈现模块化设计,将逻辑分离到专用进程以利清晰度和综合器友好。

实体

实体定义两个泛型参数——ram_width 和 ram_depth——设定字宽和 FIFO 深度。有效容量为 ram_depth - 1,因保留一个槽位区分满/空。

entity axi_fifo is generic ( ram_width : natural; ram_depth : natural ); port ( clk : in std_logic; rst : in std_logic; -- AXI input interface in_ready : out std_logic; in_valid : in std_logic; in_data : in std_logic_vector(ram_width - 1 downto 0); -- AXI output interface out_ready : in std_logic; out_valid : out std_logic; out_data : out std_logic_vector(ram_width - 1 downto 0) ); end axi_fifo; 

接口遵循 AXI 惯例:输入侧用 in_ready 和 in_valid,输出侧镜像信号但方向反转。此对称性允许多 FIFO 无缝级联。

信号声明

先定义匹配泛型宽深的 RAM 类型,再实例化数组:

-- The FIFO is full when the RAM contains ram_depth - 1 elements type ram_type is array (0 to ram_depth - 1) of std_logic_vector(in_data'range); signal ram : ram_type; 

声明可表示 RAM 任意地址的索引子类型,及四个核心信号:head、tail、count、延迟副本 count_p1:

subtype index_type is natural range ram_type'range; signal head : index_type; signal tail : index_type; signal count : index_type; signal count_p1 : index_type; 

保存 ready/valid 输出内部版本,避免架构内读 out 信号:

signal in_ready_i : std_logic; signal out_valid_i : std_logic; 

辅助信号跟踪上周期是否同时发生读写,对正确设置近空时 out_valid 关键:

signal read_while_write_p1 : std_logic; 

子程序

next_index 函数根据读/写握手完成情况决定下一地址,到达数组末尾时绕回。

function next_index( index : index_type; ready : std_logic; valid : std_logic) return index_type is begin if ready = '1' and valid = '1' then if index = index_type'high then return index_type'low; else return index + 1; end if; end if; return index; end function; 

index_proc 过程封装同步更新 head 或 tail 指针的逻辑。避免重复代码,保持架构整洁。

procedure index_proc( signal clk : in std_logic; signal rst : in std_logic; signal index : inout index_type; signal ready : in std_logic; signal valid : in std_logic) is begin if rising_edge(clk) then if rst = '1' then index <= index_type'low; else index <= next_index(index, ready, valid); end if; end if; end procedure; 

内部信号赋给输出

in_ready <= in_ready_i; out_valid <= out_valid_i; 

更新头尾指针

实例化辅助过程两次——一次写指针 (head),一次读指针 (tail):

PROC_HEAD : index_proc(clk, rst, head, in_ready_i, in_valid); PROC_TAIL : index_proc(clk, rst, tail, out_ready, out_valid_i); 

推断块 RAM

大多数 FPGA 块 RAM 为同步。为让综合器推断 RAM 原语,将读写操作置于时钟进程内,避免显式使能信号:

PROC_RAM : process(clk) begin if rising_edge(clk) then ram(head) <= in_data; out_data <= ram(next_index(tail, out_ready, out_valid_i)); end if; end process; 

in_valid 高周期无条件写入,读数据每周期更新以便消费者在 FIFO 有数据时观测有效字。

统计 FIFO 元素数

count 信号反映当前占用。head 领先 tail 时计数为差值;头指针绕回时加总深度:

PROC_COUNT : process(head, tail) begin if head < tail then count <= head - tail + ram_depth; else count <= head - tail; end if; end process; 

延迟副本 count_p1 用于检测上周期 FIFO 为空,影响 out_valid:

PROC_COUNT_P1 : process(clk) begin if rising_edge(clk) then if rst = '1' then count_p1 <= 0; else count_p1 <= count; end if; end if; end process; 

更新 ready 输出

写入方应知 FIFO 能否接受更多数据。count 小于 ram_depth - 1 时 ready 置高:

PROC_IN_READY : process(count) begin if count < ram_depth - 1 then in_ready_i <= '1'; else in_ready_i <= '0'; end if; end process; 

检测同步读写

同周期读写发生时,FIFO 占用不变,但内部状态须反映近空时值将在两周期后才可用。故在 read_while_write_p1 捕获此事件:

PROC_READ_WHILE_WRITE_P1: process(clk) begin if rising_edge(clk) then if rst = '1' then read_while_write_p1 <= '0'; else read_while_write_p1 <= '0'; if in_ready_i = '1' and in_valid = '1' and out_ready = '1' and out_valid_i = '1' then read_while_write_p1 <= '1'; end if; end if; end if; end process; 

更新 valid 输出

out_valid 告诉下游逻辑何时 out_data 持有可用字。下面组合进程默认置高,两种边界情况清零:

PROC_OUT_VALID : process(count, count_p1, read_while_write_p1) begin out_valid_i <= '1'; -- If the FIFO is empty or was empty in the previous cycle if count = 0 or count_p1 = 0 then out_valid_i <= '0'; end if; -- If a simultaneous read/write occurred when the FIFO had only one item if count = 1 and read_while_write_p1 = '1' then out_valid_i <= '0'; end if; end process; 

第一条件保证首次写入后的传播延迟期间 out_valid 保持低。第二条件防止 FIFO 看似保持满一周期实则无数据输出的情况。

在 Vivado 中综合

在 Xilinx Vivado 综合此设计,在 Settings 对话框 (General → Generics/Parameters) 为泛型提供具体值。选择匹配目标 Zynq 器件 RAMB36E1 原语的深度。实现后资源利用适度——一个块 RAM 加少量 LUT 和 FF。

基于 Ready/Valid 握手在块 RAM 中实现 AXI FIFO

基于 Ready/Valid 握手在块 RAM 中实现 AXI FIFO

AXI 不止 Ready/Valid

AXI (Advanced eXtensible Interface) 是 ARM AMBA 总线架构组成部分,除简单 ready/valid 握手外提供丰富特性。深入理解可参考:


VHDL

  1. 工业互联网:以连接、分析与用户体验重塑资产管理
  2. 资产追踪最佳实践:释放资产数据价值
  3. 数据驱动自动化优化维修供应链:从非结构文本到结构化洞察
  4. 数据驱动供应链:赋能未来物流
  5. 确保可信供应链数据:经验证的策略
  6. AI如何破解供应链“脏数据”困局:从人工清洗到算法智能
  7. 云革命:云计算如何重塑IT、安全与职业生涯
  8. 释放IoT数据价值:业务规则管理驱动企业级增值
  9. 借助物联网为 AI 做好制造运营准备
  10. 深化物联网洞察:善用数据可视化与图数据库
  11. 餐饮业最大化利用物联网:提升效率、减少浪费、愉悦顾客
  12. 用 VHDL TEXTIO 库从文本文件初始化 FPGA 块 RAM