注意:学习笔记,重点记录,后续会进行修改,参考《从零开始写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总线上不同的主设备切换是需要一个时钟周期的,因此如果想要在执行阶段读取到外设的数据,则需要在译码阶段就发出总线访问请求。

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