问题背景:模块A内部有一块RAM作为内部状态信息缓存,这个信息一方面需要被内部逻辑进行读写,一方面又需要被外部CPU总线读写,此时已经在模块A中分了时隙用于同时处理两个接口访问。现在模块B也需要对模块A中的RAM进行访问,并且优先级比CPU总线要高,因为外部CPU访问没那么紧急,都是可以挂起等待的。这个时候如果再额外增加一组总线用于连接模块A和模块B,那处理逻辑是很复杂的,所以我们可以复用CPU总线,在外部CPU和模块A之间新增一个模块用于接管这个总线并且进行调度,保证模块B一定是高优先级访问,在B模块读写时屏蔽外部的CPU信号。

一、问题简化描述

1)外部CPU访问接口

module A#(
    parameter ADDR_WIDTH = 2,
    parameter DATA_WIDTH = 2
)
(
    input clk,
    input rst_n,
    input cpu_wr,
    input [ADDR_WIDTH -1 :0] cpu_waddr,
    input [DATA_WIDTH -1 :0] cpu_datain,
    input cpu_rd,
    input [ADDR_WIDTH -1 :0] cpu_raddr,
    output cpu_dataout,
    output cpu_rd_ack,
    output cpu_wr_ack
)

localparam REG_NUM = 1 << ADDR_WIDTH;  // 2^ADDR_WIDTH 个寄存器
localparam ACK_DELAY = 10;
reg [DATA_WIDTH-1:0] reg_file [0:REG_NUM-1];
reg [ACK_DELAY-1 :0] rd_in;
reg [ACK_DELAY-1 :0] wr_in;

always @(posedge clk ) begin
    if (rst_n == 1'd0) begin
        rd_in <= {(ACK_DELAY){1'd0}};
        wr_in <= {(ACK_DELAY){1'd0}};
    end 
    else begin
        rd_in <= {rd_in[ACK_DELAY-2:0],cpu_rd};
        wr_in <= {wr_in[ACK_DELAY-2:0],cpu_wr};
    end
end


integer i;
always @(posedge clk ) begin
    if (rst_n == 1'd0) begin
        for (i = 0; i < REG_NUM; i = i + 1)
            reg_file[i] <= {DATA_WIDTH{1'b0}};
        cpu_wr_ack <= 1'b0;
    end 
    else begin
        if (cpu_wr) begin
            reg_file[cpu_waddr] <= cpu_datain;
            cpu_wr_ack <= ~wr_in[ACK_DELAY-1] & wr_in[ACK_DELAY-2];          // 写完成应答(ACK_DELAY 拍延迟)
        end
        else begin
            reg_file <= reg_file;
            cpu_wr_ack <= 1'b0;   
        end
    end
end

always @(posedge clk ) begin
    if ( ~rd_in[ACK_DELAY-1] & rd_in[ACK_DELAY-2]) begin
        cpu_dataout = reg_file[cpu_raddr];
        cpu_rd_ack  = 1'b1;
    end 
    else begin
        cpu_dataout = {DATA_WIDTH{1'b0}};  
        cpu_rd_ack  = 1'b0;
    end
end

endmodule

时序图大致为(通常ack传回cpu会消耗clk,所以cpu_wr不是立刻拉低):

2)高优先级周期性访问接口

假设高优先级的端口需要周期性访问模块A中的寄存器(一共4个),满足以下规则:

  • 每32拍读一次,一次读取一个寄存器

  • 从0到3轮询读取

  • 读完一轮之后由参数GAP控制下一次读取

  • 需要完全保证读出数据能够稳定上送,不被外部CPU访问影响。

3)具有超时告警的外部CPU访问模块

通常外部CPU访问接口长时间没有得到ack之后会拉起告警信号,防止CPU挂死。这里假设CPU从拉高rd或者wr信号之后,需要在32个周期内得到ack,否则会上报告警,示意图如下: