PreDecode

子模块:PreDecoder简介

预译码器PreDeocoder接受初始指令码并进行指令码拼接,拼接之后对每个指令码查询预译码表产生预译码信息,预译码信息包括该位置是否是有效指令开始、CFI指令类型、是否是RVC指令、是否是Call指令以及是否是Ret指令。预译码器会产生两种有效指令开始的向量,一种是默认第1个二字节必为有效指令开始,另一种是默认第2个二字节必为有效指令的开始,最终的选择在IFU端做。

所以,预译码器接收的输入是: 17 x 2B的初始指令码,这个2字节的初始指令码要么是一条RVC指令,要么是一条RVI指令的前半或后半部分。

预译码器的输出是:16x4B的拼接指令码;对每个4B指令码,该条指令是否为RVI或RVC指令(RVC指令只考虑该4B的低2B);对每个4B指令码,该条指令的跳转偏移;两个16位的有效指令开始向量,其中第一种向量假定当前预测块的起始2字节为一条有效指令的开始,而第二种向量假定当前预测块的起始2字节为一条有效RVI指令的结束(但是由于第二种向量的前两位必然为0和1,所以编译优化后,第二种向量实际只有14个信号,表示2-15位;同理,第1种向量的第0位因为恒为1,所以也被优化)

功能介绍

指令码生成

预译码器接受来自IFU完成指令切分的17 × 2字节的初始指令码,并以4字节为窗口,2字节为步进长度, 从第1个2字节开始,直到第16个2字节,选出总共16个4字节的指令码。

预译码信息生成

预译码器根据指令码产生预译码信息,主要包括:是否是RVC指令、是否是CFI指令、 CFI指令类型(branch/jal/jalr/call/ret)、CFI指令的目标地址计算偏移。

首先是判断是否是RVC指令,RVC指令的具体格式参阅RISCV手册的描述:

RVC

其中,决定指令是否为RVC的部分在于指令的[1, 0]两位,不为3的情况下都是RVC指令。

其余的指令性质判定功能(CFI类型、是否为call和ret)被时序优化到了F3PreDecoder中,不过也可以认为是PreDecoder的一部分。

最后比较麻烦的是CFI指令的目标地址计算偏移,主要是对J和BR分支指令进行的计算,这需要综合RVI和RVC中jal和br指令的结构。 首先,是手册中对于C.J的描述

JOP

这里对imm立即数的注解是,立即数的每一位最后对应到的是偏移的哪一位。

所以,可以认为立即数是这么重组的:

instr(12) + instr(8) + instr(10, 9) + instr(6) + instr(7) + instr(2) + instr(11) +instr(5,3) + “0”

而RVI中,对于JAL指令,是这么定义的:

RVIJ

我们可以类似地计算立即数。

同样的,我们可以查询手册,参考BR类指令的立即数计算RVC和RVI指令对应的偏移。

RVIBR

RVCBR

PreDecode接口说明

输入接口

in_bits_data 17 x 2B的初始指令码,其中,每2个字节既可以代表一条RVC指令,也可以代表一个RVI指令的一半。

输出接口

instr:拼接后的 16 x 4B的初始指令码

jumpOffset:如果这条指令是跳转指令,则jumpOffset表示其跳转偏移

pd:每条指令预译码信息,在时序优化之后,PreDecode模块的控制信息只剩下了valid和isRVC,后者表示这条指令是否为RVC指令

hasHalfValid:这个信号需要和pd的valid结合起来看,PreDecode的一个功能是求出指令开始向量,也就是对每个4B的拼接指令,判断其低2B是否为一条有效指令的开始(即一条RVI指令的前半部分,或者一条RVC指令),但是需要分类讨论该预测块的第一个2B是否为一条有效指令的开始。hasHalfValid表示的是当前预测块的第一个2B指令为一条RVI指令的后半部分时,给出的指令开始向量。类似地,pd中的valid指的是当前预测块的第一个2B指令为一条指令的开始时,给出的指令开始向量。

PreDecoder测试点和功能点

功能点1 生成指令码

子模块:PreDecoder简介

预译码器PreDeocoder接受初始指令码并进行指令码拼接,拼接之后对每个指令码查询预译码表产生预译码信息,预译码信息包括该位置是否是有效指令开始、CFI指令类型、是否是RVC指令、是否是Call指令以及是否是Ret指令。预译码器会产生两种有效指令开始的向量,一种是默认第1个二字节必为有效指令开始,另一种是默认第2个二字节必为有效指令的开始,最终的选择在IFU端做。

所以,预译码器接收的输入是: 17 x 2B的初始指令码,这个2字节的初始指令码要么是一条RVC指令,要么是一条RVI指令的前半或后半部分。

预译码器的输出是:16x4B的拼接指令码;对每个4B指令码,该条指令是否为RVI或RVC指令(RVC指令只考虑该4B的低2B);对每个4B指令码,该条指令的跳转偏移;两个16位的有效指令开始向量,其中第一种向量假定当前预测块的起始2字节为一条有效指令的开始,而第二种向量假定当前预测块的起始2字节为一条有效RVI指令的结束(但是由于第二种向量的前两位必然为0和1,所以编译优化后,第二种向量实际只有14个信号,表示2-15位;同理,第1种向量的第0位因为恒为1,所以也被优化) 功能介绍 指令码生成

预译码器接受来自IFU完成指令切分的17 × 2字节的初始指令码,并以4字节为窗口,2字节为步进长度, 从第1个2字节开始,直到第16个2字节,选出总共16个4字节的指令码。 预译码信息生成

预译码器根据指令码产生预译码信息,主要包括:是否是RVC指令、是否是CFI指令、 CFI指令类型(branch/jal/jalr/call/ret)、CFI指令的目标地址计算偏移。

预译码器从IFU接收完成指令切分的17 x 2 字节的初始指令码,以4字节为窗口,2字节为步进长度,选出16 x 4字节的指令码

我们需要随机生成初始指令码,并测试拼接的结果。

序号 名称 描述
1 拼接测试 随机生成17 x 2字节的初始指令码,检验PreDecoder拼接结果

功能点2 生成预译码信息

预译码器会根据指令码产生预译码信息,包括RVC指令的判定和CFI指令的目标地址计算偏移。

CFI类型的判定则时序优化到了F3PreDecoder中。

据此,我们可以设计下述测试点。

首先是判定RVC指令,我们随机生成输入初始指令码,对返回的16位RVC判定结果进行检验。 具体来说,对每32位指令,考虑RVC和RVI两种情况。

序号 名称 描述
2.1.1 RVC判定 传入RVC指令,应该判断为RVC
2.1.2 RVI判定 传入RVI指令,不应判断为RVC

然后,需要分别根据手册构造RVC和RVI扩展下的J指令和BR指令们,所以有如下的测试点:

序号 名称 描述
2.2.1 RVC.J计算 对传入RVC扩展的J指令,检查计算的偏移
2.2.2 RVI.J计算 对传入RVI扩展的J指令,检查计算的偏移
2.2.3 RVC.BR计算 对传入RVC扩展的BR指令,检查计算的偏移
2.2.4 RVI.BR计算 对传入RVI扩展的BR指令,检查计算的偏移

功能点3 生成指令开始向量

最后,预译码还需要生成两种指令开始向量:

序号 名称 描述
2.3.1 有效指令开始向量计算1 对预测块,假定第一条指令为一条有效指令的开始,对每条指令计算其是否为有效指令开始
2.3.2 有效指令开始向量计算2 对预测块,假定第一条指令为一条有效指令的结束,对每条指令计算其是否为有效指令开始

测试点汇总

综上所述,对PredDecoder,所有的测试点为:

序号 功能 名称 描述
1 拼接指令码 拼接测试 随机生成17 x 2字节的初始指令码,检验PreDecoder拼接结果
2.1.1 RVC判定 RVC判定 传入RVC指令,应该判断为RVC
2.1.2 RVC判定 RVI判定 传入RVI指令,不应判断为RVC
2.2.1 跳转目标计算 RVC.J计算 对传入RVC扩展的J指令,检查计算的偏移
2.2.2 跳转目标计算 RVI.J计算 对传入RVI扩展的J指令,检查计算的偏移
2.2.3 跳转目标计算 RVC.BR计算 对传入RVC扩展的BR指令,检查计算的偏移
2.2.4 跳转目标计算 RVI.BR计算 对传入RVI扩展的BR指令,检查计算的偏移
2.3.1 有效指令开始向量计算1 对预测块,假定第一条指令为一条有效指令的开始,对每条指令计算其是否为有效指令开始
2.3.2 有效指令开始向量计算2 对预测块,假定第一条指令为一条有效指令的结束,对每条指令计算其是否为有效指令开始
最后修改 February 22, 2025: ifu top rtl build scripts modify (#76) (5520758)