4、握手信号定义:从协议到实战

握手信号,说白了就是两个模块之间「你一句我一句」的沟通方式。我做了十几年IC设计,见过太多因为握手没处理好导致的bug。今天咱们就把这几种常见的握手方式掰开揉碎了讲清楚。

4.1 req/ack握手协议

这是最经典的握手方式,也是我入行时学的第一种。它的核心思想很简单:发送方先拉高req(请求),接收方处理完后拉高ack(应答)。

典型时序流程:

  • 发送方准备好数据,拉高req
  • 接收方看到req,开始处理
  • 处理完成,拉高ack
  • 发送方看到ack,拉低req
  • 接收方看到req变低,拉低ack

嗯,这里要注意:req和ack之间不能有组合逻辑环路。我曾经在一个项目中,因为图省事把req直接连到了ack的生成逻辑上,结果仿真时出现了死锁。排查了整整两天才找到问题。

// 典型的req/ack握手实现
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        req <= 1'b0;
        data <= 32'b0;
    end else begin
        if (send_en && !req) begin
            req <= 1'b1;      // 发起请求
            data <= send_data;
        end else if (ack) begin
            req <= 1'b0;      // 收到应答,撤销请求
        end
    end
end

4.2 valid/ready握手机制

这种机制在AXI总线里用得最多。我个人习惯把它叫做「背靠背」握手——发送方说「我有数据」(valid),接收方说「我能接收」(ready),两边都同意,数据就传过去了。

你想想看,这和req/ack最大的区别是什么?valid/ready是并行的,双方可以同时表达意愿。而req/ack是串行的,必须一问一答。

实战经验:

我在做DMA控制器时,遇到过valid和ready同时拉高的场景。这时候数据必须在同一个时钟周期内完成传输。很多新手会在这里犯错——以为valid和ready需要分先后。其实它们可以同时有效,这就是所谓的「零等待传输」。

// valid/ready握手示例
always @(posedge clk) begin
    if (valid && ready) begin
        // 数据在同一个时钟周期传输
        fifo_wr_en <= 1'b1;
        fifo_wr_data <= bus_data;
    end
end

4.3 全握手 vs 半握手

这个对比很有意思。我刚开始带团队时,让两个工程师分别实现全握手和半握手,结果他们吵起来了——都说自己的方案更好。其实各有适用场景。

对比项 全握手 半握手
握手信号 req + ack,四边沿握手 只有valid,或只有ready
可靠性 高,每拍都确认 低,可能丢数据
吞吐量 低,每拍都要等ack 高,可以连续传输
适用场景 控制类、配置类接口 数据流、视频处理

避坑指南:

我曾经在一个视频处理项目中,为了追求吞吐量用了半握手。结果发现接收端偶尔会丢数据——因为发送端连续发了两个valid,但接收端只处理了第一个。从那以后,凡是涉及控制信号的,我坚决用全握手。

4.4 跨时钟域握手

这是握手信号里最头疼的问题。两个时钟域之间传握手信号,搞不好就是亚稳态、数据不一致。

我的做法是:能打两拍就绝不只打一拍。但光打拍子还不够,还要考虑握手信号的宽度问题。

跨时钟域握手的标准做法:

  1. 发送域:将数据锁存,然后发送req
  2. 接收域:对req打两拍同步
  3. 接收域:采样数据,发送ack
  4. 发送域:对ack打两拍同步
  5. 发送域:看到ack后,可以发下一笔数据
// 跨时钟域握手同步
// 接收域同步req
always @(posedge clk_b or negedge rst_n) begin
    if (!rst_n) begin
        req_sync1 <= 1'b0;
        req_sync2 <= 1'b0;
    end else begin
        req_sync1 <= req_a;      // 第一拍
        req_sync2 <= req_sync1;  // 第二拍
    end
end

说白了,跨时钟域握手就是「慢工出细活」。我见过有人为了省两拍延迟,直接用单拍同步,结果芯片跑起来后偶尔出现数据错误。这种问题在仿真时很难复现,一旦量产就麻烦了。

我的建议:

如果你不确定跨时钟域握手是否可靠,可以用一个简单的验证方法:在发送域连续发1000笔数据,接收域全部收回来后做CRC校验。如果有一笔错了,就说明你的握手逻辑有问题。这个方法我在多个项目中都用过,屡试不爽。

握手信号知识体系 req/ack握手 valid/ready握手 全握手 vs 半握手 跨时钟域握手 串行一问一答 控制类接口常用 并行双向握手 AXI总线标准 可靠性 vs 吞吐量 根据场景选择 双拍同步 亚稳态处理 核心:根据应用场景选择合适的握手方式

好了,以上就是握手信号的四种核心机制。每种都有它的脾气,用对了事半功倍,用错了...嗯,你可能就要像我一样熬夜debug了。

可可精品资料库