问题背景:模块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,否则会上报告警,示意图如下:
评论