外部接口¶
本部分叙述 Thruster 在 独立模式 下生成的 RTL 模块向外部暴露的接口定义,及其行为描述。除了 clock 和 reset 信号,接口分为控制和数据两部分,其中控制部分的 RoCC 接口是强制的,数据部分在 TileLink 和 AXI 中二选一。
控制部分¶
此部分为 Thruster 与控制核相连的接口。
RoCC 接口¶
接口定义¶
Thruster 使用(经过简化的)标准 RoCC 接口与控制核进行通信。这一接口在 Rocket Chip 中定义为 RoCCCoreIO 类型,在 Thruster 中定义为 ThrusterRoCCCoreIO 类型。
Warning
ThrusterRoCCCoreIO 与标准 RoCCCoreIO 相比缺少一些字段,并且在 RTL 中所有数据名称被展平了。
| 信号名称 | 长度 | 说明 |
|---|---|---|
rocc_cmd_{valid,ready} |
1 | 控制核向 VP 发送指令的握手信号 |
rocc_cmd_bits_inst_funct |
7 | RoCC 指令 funct 字段 |
rocc_cmd_bits_inst_{rs2,rs1} |
5 | RoCC 指令 rs2, rs1 字段 |
rocc_cmd_bits_inst_{xd,xs1,xs2} |
1 | RoCC 指令 xd, xs1, xs2 字段 |
rocc_cmd_bits_inst_rd |
5 | RoCC 指令 rd 字段 |
rocc_cmd_bits_inst_opcode |
7 | RoCC 指令 opcode 字段(固定为某个值) |
rocc_cmd_bits_{rs1,rs2} |
XLEN |
RoCC 指令中 rs1. rs2 对应的寄存器值 |
rocc_resp_{ready,valid} |
1 | VP 向控制核写回结果的握手信号 |
rocc_resp_bits_rd |
5 | 写回结果的目标寄存器(固定为 rd) |
rocc_resp_bits_data |
XLEN |
写回寄存器的数据 |
rocc_busy |
1 | VP 正在进行运算 |
rocc_interrupt |
1 | VP 需要进行中断(当前始终拉低) |
上述 rocc_cmd_bits_inst_* 字段按顺序连接即为 32 位的 RoCC 指令。对于同一个 RoCC,opcode 字段固定为下列之一:
custom0:0001011custom1:0101011custom2:1011011custom3:1111011
行为描述¶
在控制核解析到注册的 RoCC 指令时(即 opcode 匹配给定的字段),应该与 RoCC 进行握手(即拉高 valid),并在同一个周期填充 rocc_cmd_* 所有相关字段,特别是读出的寄存器值(可以在执行或写回阶段进行)。如果 xs1, xs2 中的某个为低,说明 RoCC 不需要对应的寄存器值(传 0 ),控制核也无需真正读取该寄存器,这可以帮助减少 RoCC 指令与控制核流水线中前面指令的数据冲突。
在 RoCC 接受指令(即拉高 ready)完成后,控制核应该如下工作:
- 如果正在执行的 RoCC 指令需要写寄存器(
xd=1),则控制核可以继续执行指令。但是如果发生冲突(即当前 RoCC 指令的目标寄存器是将要执行指令的源寄存器),则需要等待 RoCC 指令完成(即等待 RoCC 完成rocc_resp_*信号的握手),并完成相应寄存器写回后(保证 RoCC 请求写回的rd与对应指令给出的rd一致),方可继续执行; - 如果正在执行的 RoCC 指令不需要写寄存器(
xd=0),则控制核可以继续执行,无需等待rocc_resp_*的握手,RoCC 也不会进行握手操作(rocc_resp_valid=0)。
在任何时候,当控制核遇到 FENCE 指令时,都需要额外检查 RoCC 的 busy 状态。如果 FENCE 指令与内存有关(即含有 PR/PW/SR/SW 中的任何一个标记),则控制核必须等待 RoCC 不再置位 busy 后方可继续执行。
由于在初版实现中 RoCC 与控制核并不共享内存空间,并且上面的做法也消除了寄存器的冲突,因此 RoCC 与控制核不会发生数据冲突。
交互示例¶
下面是 RoCC 接口通信的例子:
Note
在实际向量处理器的设计中,RoCC 的配置指令(如 vsetvl)需要写回寄存器,而控制指令(如 vf)则不需要;前者会立刻返回,而后者实际进行计算。为了简单起见,我们推荐对于 xd=1 的指令,控制核可以直接阻塞直到完成写回,并不会影响性能。
Page Table Walker 接口(可选)¶
Thruster 使用这一接口,查询控制核当前的页表,以进行虚拟地址到物理地址的转换,并缓存于自己的 TLB 中。如果不启用这个接口,所涉及到的地址都是物理地址。
Info
目前 Thruster 不需要此功能,因此未引出此接口。
ptw_req_read, ptw_req_valid: 向 PTW 发起地址查询请求
ptw_req_bits_bits_addr: 查询的虚拟地址
ptw_resp_valid: PTW 返回地址查询结果
ptw_resp_bits_pte_*: 查询到的 PTE
ptw_resp_bits_level: 查询到的页表级数
FPU 接口(可选)¶
此接口用于 Thruster 请求控制核的 FPU 进行运算。如果不启用这个接口,则使用内置的 FPU。
Info
目前 Thruster 不需要此功能,因此未引出此接口。
fpu_req_ready, fpu_req_valid: 向 FPU 发起请求
fpu_req_bits_*: FPU 执行的 OpCode 和参数
fpu_resp_valid: FPU 计算结束
fpu_resp_bits_data: FPU 返回的结果
数据部分¶
此部分为 Thruster 与内存总线相连的接口。由于向量核自身具有指令和数据缓存,因此需要独立地进行访存操作。数据接口需要在 AXI 接口和 TileLink 接口中二选一。
Info
Thruster 内部的访存均使用 TileLink,AXI 接口由 TileLink 转换而来。
AXI 总线版本¶
独立模块版本的 Thruster 默认引出 AXI 接口,定义如下:
mem_ar_*: AXI 总线的 AR Channel
mem_r_*: AXI 总线的 R Channel
mem_aw_*: AXI 总线的 AW Channel
mem_w_*: AXI 总线的 W Channel
mem_b_*: AXI 总线的 B Channel
其接口定义与行为遵循标准的 AMBA AXI 4 协议,在此不再赘述。
TileLink 总线版本¶
RoCC 版本的 Thruster 并不引出数据接口,而是直接挂接在 Rocket Chip 内部的 TileLink 总线上。
tl_out_a_*: 连接到 L2 的 TileLink 总线的 A Channel
tl_out_d_*: 连接到 L2 的 TileLink 总线的 D Channel
atl_out_a_*: 连接到 L1 的 TileLink 总线的 A Channel
atl_out_d_*: 连接到 L1 的 TileLink 总线的 D Channel
例子¶
当前 Thruster 的模块接口定义为:
module Thruster(
input clock,
input reset,
input mem_0_aw_ready,
output mem_0_aw_valid,
output mem_0_aw_bits_id,
output [31:0] mem_0_aw_bits_addr,
output [7:0] mem_0_aw_bits_len,
output [2:0] mem_0_aw_bits_size,
output [1:0] mem_0_aw_bits_burst,
output mem_0_aw_bits_lock,
output [3:0] mem_0_aw_bits_cache,
output [2:0] mem_0_aw_bits_prot,
output [3:0] mem_0_aw_bits_qos,
output [4:0] mem_0_aw_bits_user,
input mem_0_w_ready,
output mem_0_w_valid,
output [127:0] mem_0_w_bits_data,
output [15:0] mem_0_w_bits_strb,
output mem_0_w_bits_last,
output mem_0_b_ready,
input mem_0_b_valid,
input mem_0_b_bits_id,
input [1:0] mem_0_b_bits_resp,
input [4:0] mem_0_b_bits_user,
input mem_0_ar_ready,
output mem_0_ar_valid,
output mem_0_ar_bits_id,
output [31:0] mem_0_ar_bits_addr,
output [7:0] mem_0_ar_bits_len,
output [2:0] mem_0_ar_bits_size,
output [1:0] mem_0_ar_bits_burst,
output mem_0_ar_bits_lock,
output [3:0] mem_0_ar_bits_cache,
output [2:0] mem_0_ar_bits_prot,
output [3:0] mem_0_ar_bits_qos,
output [4:0] mem_0_ar_bits_user,
output mem_0_r_ready,
input mem_0_r_valid,
input mem_0_r_bits_id,
input [127:0] mem_0_r_bits_data,
input [1:0] mem_0_r_bits_resp,
input [4:0] mem_0_r_bits_user,
input mem_0_r_bits_last,
output rocc_cmd_ready,
input rocc_cmd_valid,
input [6:0] rocc_cmd_bits_inst_funct,
input [4:0] rocc_cmd_bits_inst_rs2,
input [4:0] rocc_cmd_bits_inst_rs1,
input rocc_cmd_bits_inst_xd,
input rocc_cmd_bits_inst_xs1,
input rocc_cmd_bits_inst_xs2,
input [4:0] rocc_cmd_bits_inst_rd,
input [6:0] rocc_cmd_bits_inst_opcode,
input [63:0] rocc_cmd_bits_rs1,
input [63:0] rocc_cmd_bits_rs2,
input rocc_resp_ready,
output rocc_resp_valid,
output [4:0] rocc_resp_bits_rd,
output [63:0] rocc_resp_bits_data,
output rocc_busy,
output rocc_interrupt
);