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的部分在于指令的[1, 0]两位,不为3的情况下都是RVC指令。
其余的指令性质判定功能(CFI类型、是否为call和ret)被时序优化到了F3PreDecoder中,不过也可以认为是PreDecoder的一部分。
最后比较麻烦的是CFI指令的目标地址计算偏移,主要是对J和BR分支指令进行的计算,这需要综合RVI和RVC中jal和br指令的结构。 首先,是手册中对于C.J的描述
这里对imm立即数的注解是,立即数的每一位最后对应到的是偏移的哪一位。
所以,可以认为立即数是这么重组的:
instr(12) + instr(8) + instr(10, 9) + instr(6) + instr(7) + instr(2) + instr(11) +instr(5,3) + “0”
而RVI中,对于JAL指令,是这么定义的:
我们可以类似地计算立即数。
同样的,我们可以查询手册,参考BR类指令的立即数计算RVC和RVI指令对应的偏移。
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 | 对预测块,假定第一条指令为一条有效指令的结束,对每条指令计算其是否为有效指令开始 |