总线模块详解

总线模块详解注意 学习笔记 重点记录 后续会进行修改 参考 从零开始写 RISC V 处理器 一个没有总线的 SOC 处理器核与外设之间的连接是怎样的 可能会如下图所示 可见 处理器核 core 直接与每个外设进行交互 假设一个外设有一条地址总线和一条数据总线

大家好,我是讯享网,很高兴认识大家。

注意:学习笔记,重点记录,后续会进行修改,参考《从零开始写RISC-V处理器》。

一个没有总线的SOC,处理器核与外设之间的连接是怎样的。可能会如下图所示:


讯享网

 可见,处理器核core直接与每个外设进行交互。假设一个外设有一条地址总线和一条数据总线,总共有N个外设,那么处理器核就有N条地址总线和N条数据总线,而且每增加一个外设就要修改(改动还不小)core的代码。有了总线之后(见本章开头的图2_1),处理器核只需要一条地址总线和一条数据总线,大大简化了处理器核与外设之间的连接。

目前已经有不少成熟、标准的总线,比如AMBA、wishbone、AXI等。设计CPU时大可以直接使用其中某一种,以节省开发时间。但是为了追求简单,tinyriscv并没有使用这些总线,而是自主设计了一种名为RIB(RISC-V Internal Bus)的总线。RIB总线支持多主多从连接,但是同一时刻只支持一主一从通信。RIB总线上的各个主设备之间采用固定优先级仲裁机制

RIB总线模块的输入输出信号如下表所示(由于各个主、从之间的信号是类似的,所以这里只列出其中一个主和一个从的信号):

序号 信号名 输入/输出 位宽(bits) 说明
1 m0_addr_i 输入 32 主设备0读写外设地址
2 m0_data_i 输入 32 主设备0写外设数据
3 m0_data_o 输出 32 主设备0读取到的数据
4 m0_ack_o 输出 1 主设备0访问完成标志
5 m0_req_i 输入 1 主设备0访问请求标志
6 m0_we_i 输入 1 主设备0写标志
7 s0_addr_o 输出 32 从设备0读、写地址
8 s0_data_o 输出 32 从设备0写数据
9 s0_data_i 输入 32 从设备0读取到的数据
10 s0_ack_i 输入 1 从设备0访问完成标志
11 s0_req_o 输出 1 从设备0访问请求标志
12 s0_we_o 输出 1 从设备0写标志

RIB总线本质上是一个多路选择器,从多个主设备中选择其中一个来访问对应的从设备。

RIB总线地址的最高4位决定要访问的是哪一个从设备,因此最多支持16个从设备。

仲裁方式采用的类似状态机的方式来实现,代码如下所示:

 

... // 主设备请求信号 assign req = {m2_req_i, m1_req_i, m0_req_i}; // 授权主设备切换 always @ (posedge clk) begin if (rst == `RstEnable) begin grant <= grant1; end else begin grant <= next_grant; end end //切换主设备操作,默认是授权给主设备1的,即取指模块。从这里可以知道,从发出总线访问请求后,需要一个时钟周期才能完成切换 // 仲裁逻辑,通过组合逻辑电路来实现优先级仲裁 // 固定优先级仲裁机制 // 优先级由高到低:主设备0,主设备2,主设备1 always @ (*) begin if (rst == `RstEnable) begin next_grant = grant1; //默认授权给主设备1 hold_flag_o = `HoldDisable; end else begin case (grant) grant0: begin//授权给主设备0的情况,通过if、else语句来实现优先级 if (req[0]) begin//主设备0的请求 next_grant = grant0; hold_flag_o = `HoldEnable;//需要暂停流水线 end else if (req[2]) begin//主设备2的请求 next_grant = grant2; hold_flag_o = `HoldEnable;//需要暂停流水线 //此两处暂停流水线,只需要暂停PC阶段,让译码和执行阶段继续执行 end else begin next_grant = grant1; hold_flag_o = `HoldDisable; end end grant1: begin if (req[0]) begin next_grant = grant0; hold_flag_o = `HoldEnable; end else if (req[2]) begin next_grant = grant2; hold_flag_o = `HoldEnable; end else begin next_grant = grant1; hold_flag_o = `HoldDisable; end end grant2: begin if (req[0]) begin next_grant = grant0; hold_flag_o = `HoldEnable; end else if (req[2]) begin next_grant = grant2; hold_flag_o = `HoldEnable; end else begin next_grant = grant1; hold_flag_o = `HoldDisable; end end default: begin next_grant = grant1; hold_flag_o = `HoldDisable; end endcase end end ...

讯享网

注意:RIB总线上不同的主设备切换是需要一个时钟周期的,因此如果想要在执行阶段读取到外设的数据,则需要在译码阶段就发出总线访问请求。

小讯
上一篇 2025-03-11 12:26
下一篇 2025-03-12 10:06

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/14907.html