Wired 是一个由 @gmlayer0 设计实现的,基于 Loongarch32-Reduced 指令集的 CPU 核。Wired 核对先进微架构设计及对称多处理器(SMP)设计进行了尝试和探索,成功地实现了乱序多发射且支持硬件缓存一致性的内核微架构。
本核心已验证可以通过 Chiplab(Verilator)进行仿真,或者通过 Xilinx Vivado 综合到 FPGA 平台进行验证。
Wired 核心整体基于 Tomasulo 算法的思路实现动态调度,采用基于 ROB 的寄存器重命名策略,并实现了分支预测,数据旁路,推测唤醒等机制以提高流水线效率。 Wired 完整实现了 Loongarch32-Reduced 指令集中的所有整数指令及绝大部分单精度浮点指令,提供单精度浮点执行支持。对于部分特殊单精度浮点指令(frsqrt.s、fmina.s、fmaxa.s)经检查在默认配置下不会被编译器生成,也没有进行相应的实现。
Wired 在龙芯杯提供的性能测试中,可以取得 0.92 的几何平均 IPC ,并在 6 / 10 个测试点中取得 1.0 以上的绝对 IPC。在 CRC32 测试下,处理器核达到了 1.48 的 IPC,在 SHA 测试中则取得了 1.35 的 IPC 。对于分支较稀疏的计算密集程序, Wired 核可以有较为良好的表现。在最理想的指令流下,IPC 可以达到 2。
核心支持使用 Chiplab(Verilator)进行仿真。若要使用 Chiplab 仿真,请参考 Chiplab官方仓库 完成环境配置,之后设置 CHIPLAB_HOME
变量到 chiplab 家目录。
进入 ./src 目录,执行 ./compile_project.py 脚本,即可将本核心自动化部署到 Chiplab 环境之中,之后即可参考官方使用说明运行仿真程序。
核心支持使用 Vivado 进行综合,并已在 Ultrascale+ ZYNQ MPSoC(XCZU15EG) 上验证可以以四核心配置启动系统。具体 SoC 及说明请参考 WiredSoC 仓库(尚未公开)。
Wired 使用 Systemverilog 实现,全部硬件源码,包括第三方开源 IP ,均存放在 ./rtl 目录之下。
而在 ./src 目录之下存放了一些工具脚本,这里对其代码结构进行简单介绍。
-
./src/compile_project.py
Wired Core 采用的一套 python 脚本,会读取环境变量中的
CHIPLAB_HOME
并将核心部署到其环境中用于仿真。 其还使用 compile_settings.json 对使用的模块版本进行管理,每个模块的文件头部会用特殊语法标记其版本,并在 compile_settings.json 中实际选择使用的版本。 描述语法形如:
/*--JSON--{"module_name":"core_lsu_rport","module_ver":"2","module_type":"module"}--JSON--*/
这里描述了一个名为 core_lsu_rport
的模块,其版本号为 2,类型为模块(module)。
-
./src/gen_sram_wrapper_*.py
Wired Core 的设计考虑在不同的平台中使用(仿真器环境、FPGA 环境、流片环境)。在不同环境下,核心需要使用不同的模块作为存储器使用。
好在 Wired Core 设计中只使用了单口及双口的 sram,而 sram 在不同平台下具有相似接近的行为,仅存在模块名和接口名称的区别。
因此我们使用这样一个小工具,生成我们需要使用的,兼容不同平台,不同容量 sram 的生成工具生成核心使用的 sram。
-
./src/inst
Wired Core 支持使用一套 python 脚本生成核心使用的解码器及相关指令静态控制信息。这套工具使用一组 json 描述指令集。
在
./src/inst
目录中,存放默认使用的 la32r 整数指令集解码信息。其中general.json
定义一些常量,以及处理器流水线通用的一些控制信号,及流水级顺序。对于常量的定义,直接使用一个键值对即可,由常量名映射到其值。这部分会被使用
`define
定义成常量使用。形如:
"_REG_R0_IMM": "2'b11"
等价于 `define _REG_R0_IMM 2'b11
对于流水线的定义,采用一系列二元组,描述流水线关系的 DAG 图,形如:
[
["alu", "c_alu_common"],
["c", "c_alu_common"],
["rob", "c"],
["p", "alu"],
["p", "rob"],
["d", "p"],
["Entry", "d"]
]
描述了如下图的一个流水线关系: ![Alt text](https://g.gravizo.com/svg? digraph G { start -> d; d->p; p->alu; p->rob; rob->c; c->c_alu_common; alu->c_alu_common; c_alu_common->end; start [shape=Mdiamond]; end [shape=Msquare]; } )
关于流水线控制信号定义,也使用一个键值对的格式描述,如:
"imm_type": {
"length": 3,
"stage": "is",
"default_value": "`_IMM_U5"
}
这组定义描述了一个信号名为 imm_type
,且会在 is
级使用(之后流水级不使用)的控制信号。其长度为 3,默认值(不手动指定时)为字符串 `_IMM_U5
控制信号会按照其不同流水线位置,分布在不同流水级之间,并自动生成流水控制信号在各级别之间传递转换的函数。
在其它 .json
文件中,描述了指令使用的具体解码信息,及部分专用指令控制信号,形如 alu.json
中对于 add.w
指令的定义:
"add.w": {
"opcode": "00000000000100000",
"alu_grand_op":"`_ALU_GTYPE_INT",
"alu_op":"`_ALU_STYPE_ADD",
"reg_type_r0": "`_REG_RK",
"reg_type_r1": "`_REG_RJ",
"reg_type_w": "`_REG_W_RD",
"alu_inst": 1,
"das": "\"$r%02x, $r%02x, $r%02x\",rd, rj, rk"
}
其中, opcode 字段定义了指令的解码信息。大部分 LA32R 指令采用可变长的前缀解码的形式,因此只用在 opcode 中描述其前缀码即可。 对于解码时不关心的位,可以使用 x 跳过,如下指令。
"bcnez": {
"opcode": "010010xxxxxxxxxxxxxxxx01",
"fbranch_inst": 1,
"bcnez": 1,
"cmp_type": "`_CMP_E",
"target_type": "`_TARGET_REL",
"jump_inst": 1,
"das": "\"%07x\",I26<<2",
"fpd_inst": 1,
"slot0": 1
}