You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rocket Core与MMIO设备间Tilelink协议握手异常求助

Rocket Core与MMIO设备间Tilelink协议握手异常求助

看起来你在Tilelink协议握手的处理上踩了几个典型的坑,我帮你拆解下问题根源和修复方案:

一、先理清错误的直接原因

你遇到的Assertion failed: 'D' channel acknowledged for nothing inflight,是Tilelink的协议监视器检测到了违规的D通道响应:你的Slave在没有待响应的请求时,错误地发送了D通道消息,违反了Tilelink的协议规范。

二、逐个排查并修复问题

1. 测试程序的低级错误

你的reg_read64调用参数传递完全错误,导致read操作既没正确触发也没保存返回值:

// 原错误代码
reg_read64(MMIO_BASE_ADDR , slave_input_data);

// 修复后代码
slave_input_data = reg_read64(MMIO_BASE_ADDR);
printf("[CORE] Received data from slave: 0x%lx\n", slave_input_data);

reg_read64的定义只需要一个地址参数,你多传的slave_input_data是无效的,而且要把返回值赋值给变量才能看到结果。

2. Tilelink协议处理的核心逻辑错误

这是问题的重灾区,我分点说明:

(1)混淆了「需要响应/不需要响应」的请求类型

Tilelink v1中,PutFullData/PutPartialData(OP_PUT=000)是单向请求,Slave处理完后不需要返回D通道响应;只有Get、Arithmetic、Logical这类请求才需要返回D通道响应。你之前的代码错误地给Put请求发送了D响应,这直接触发了协议监视器的断言。

(2)完全遗漏了Get请求的处理逻辑

你的Slave代码只处理了OP_PUT的A通道请求,但测试程序里明确发起了Get请求(对应read操作),这会导致Get请求一直挂起,同时之前错误的D响应又和它无关,双重违规。

(3)D通道Opcode和Source ID赋值错误

  • 你用了A通道的OP_PUT=000作为D通道的Opcode,这是完全错误的:D通道有自己独立的Opcode定义,比如Get请求的响应应该用AccessAckData(3'b010)。
  • 你错误地把slave_d_source赋值为temp_sink,但应该用之前保存的请求方Source ID(temp_source),否则Master无法匹配响应和请求。

(4)状态机逻辑混乱

你的inflight_request变量管理逻辑完全错误,错误地在Put请求时标记了“待响应”,而不是在Get请求时标记。


三、修复后的Slave协议处理代码(Verilog部分)

我重新梳理了状态机,严格遵循Tilelink v1规范:

localparam OP_PUT_FULL = 3'b000;  // A通道PutFullData
localparam OP_GET = 3'b100;       // A通道Get
localparam D_OP_ACK_DATA = 3'b010;// D通道带数据响应(对应Get请求)

reg [10:0] pending_source;  // 保存待响应请求的Source ID
reg [2:0] pending_size;     // 保存待响应请求的传输大小
reg [1:0] state;
localparam IDLE = 2'd0;
localparam PROCESSING_GET = 2'd1;

reg a_fire;
reg d_fire;
reg [63:0] accumulator_data;

assign a_fire = slave_a_ready && slave_a_valid;
assign d_fire = slave_d_ready && slave_d_valid;

always @(posedge clock) begin
    if (reset) begin
        state <= IDLE;
        accumulator_data <= 64'b0;
        slave_a_ready <= 1'b0;
        slave_d_valid <= 1'b0;
        pending_source <= 11'd0;
        pending_size <= 3'd0;
    end else begin
        case (state)
            IDLE: begin
                slave_a_ready <= 1'b1;  // 常态下准备接收A通道请求
                if (a_fire) begin
                    case (slave_a_opcode)
                        OP_PUT_FULL: begin
                            // 处理PutFull请求:仅保存并累加数据,无需D响应
                            accumulator_data <= slave_a_data + 5;
                            $display("[MMIO] Processed PUT_FULL data: 0x%x → 0x%x at time %t",
                                     slave_a_data, accumulator_data, $time);
                        end
                        OP_GET: begin
                            // 处理Get请求:需要返回D响应,进入处理状态
                            $display("[MMIO] Received GET request for addr 0x%x at time %t",
                                     slave_a_address, $time);
                            // 保存响应所需的请求参数
                            pending_source <= slave_a_source[10:0];
                            pending_size <= slave_a_size;
                            // 暂时关闭A通道接收,避免并发请求
                            slave_a_ready <= 1'b0;
                            state <= PROCESSING_GET;
                        end
                        default: begin
                            $display("[MMIO] Unsupported opcode: %b", slave_a_opcode);
                        end
                    endcase
                end
            end
            PROCESSING_GET: begin
                // 组装并发送D通道响应
                slave_d_valid <= 1'b1;
                slave_d_opcode <= D_OP_ACK_DATA;
                slave_d_param <= 3'b000;
                slave_d_size <= pending_size;
                slave_d_source <= pending_source;
                slave_d_sink <= 0;
                slave_d_data <= accumulator_data;  // 返回累加后的数据
                slave_d_denied <= 1'b0;
                slave_d_corrupt <= 1'b0;

                if (d_fire) begin
                    // 响应已完成握手,回到IDLE状态
                    $display("[MMIO] Sent GET response: 0x%x at time %t", accumulator_data, $time);
                    slave_d_valid <= 1'b0;
                    slave_a_ready <= 1'b1;
                    state <= IDLE;
                end
            end
        endcase
    end
end

四、额外的Chisel配置检查

你的Chisel Slave节点配置基本没问题,但可以再确认两点:

  • AddressSet(0x70000000L, 0x0001ffffL)的地址范围和测试程序的MMIO_BASE_ADDR完全匹配,没问题;
  • supportsGet和supportsPutFull都已正确开启,确保Master的请求能被Slave接收。

五、修复后的预期输出

当你修复完所有问题后,测试程序应该会输出类似这样的结果:

TL MMIO Test

Testing Slave Interface:
[CORE] Sending data: 0xdead000000000001
[MMIO] Processed PUT_FULL data: 0xdead000000000001 → 0xdead000000000006 at time xxx
[CORE] Issuing GET request...
[MMIO] Received GET request for addr 0x70000000 at time xxx
[MMIO] Sent GET response: 0xdead000000000006 at time xxx
[CORE] Received data from slave: 0xdead000000000006

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 07:44:35