RVCExpander
子模块:RVCExpander简介
RVCExpander是IFU的子模块,负责对传入的指令进行指令扩展,并解码计算非法信息。
该模块接收的输入量是两个:一条RVC指令或者RVI指令;CSR对fs.status的使能情况。
输出量也是两个:输入指令对应的RVI指令;RVC指令是否非法。
指令扩展
如果是RVI指令,则无需扩展。
否则对RVC指令,按照手册的约定进行扩展。
非法指令判断
RVI指令永远判断为合法。
对于RVC指令的判定,详细内容参阅20240411的RISCV手册的26.8节表格列出的指令条件。
RVCExpander接口说明
输入接口
fsIsOff:表示CSR是否使能fs.status
in:传入一个32位数据,其可以是一个完整的RVI指令,也可以是低16位RVC指令+高16位为RVI指令的一半(当然低16位也有可能是RVI指令的后半部分,但是RVCExpander不会区分,可以认为RVCExpander假定传入的32位数据的低16位一定为一条指令的开始)
输出接口
ill:表示这条指令是否为非法指令
out_bits:对RVI指令,直接返回,对RVC指令,返回扩展后的32位指令。
功能点和测试点
功能点1 指令扩展
RVCExpander负责接收预译码器拼接的指令码,并进行指令扩展,如果是16位RVC指令,需要按照RISCV手册的约定完成扩展
对此,我们需要随机生成RVI指令和RVC指令,送入预译码器:
序号 | 名称 | 描述 |
---|---|---|
1.1 | RVI指令保留 | 构造RVI指令传入,检查保留情况 |
1.2 | RVC指令扩展 | 构造RVC指令传入,按手册检查扩展结果 |
功能点2 非法指令判断
RVCExpander在解析指令时,如发现指令违反了手册的约定,则需要判定该指令非法
对此,我们需要随机生成非法指令送入RVI中,并检测RVCExpander对合法位的校验;同时,我们还需要校验合法指令是否会被误判为非法指令:
此外,需要判定C.fp指令在CSR未使能fs.status的情况下,能否将这类指令判定为非法。
序号 | 名称 | 描述 |
---|---|---|
2.1 | 常规非法指令测试 | 随机构造非法RVC指令传入,检查判断结果 |
2.2 | 合法指令测试 | 随机构造合法RVC指令传入,检查判断结果 |
2.3 | C.fp指令测试 | CSR未使能fs.status的情况下,C.fp指令应该为非法 |
测试点汇总
序号 | 功能 | 名称 | 描述 |
---|---|---|---|
1.1 | 指令扩展 | RVI指令保留 | 构造RVI指令传入,检查保留情况 |
1.2 | 指令扩展 | RVC指令扩展 | 构造RVC指令传入,按手册检查扩展结果 |
2.1 | 非法指令判断 | 非法指令测试 | 随机构造非法RVC指令传入,检查判断结果 |
2.2 | 非法指令判断 | 合法指令测试 | 随机构造合法RVC指令传入,检查判断结果 |
2.3 | C.fp指令测试 | CSR未使能fs.status的情况下,C.fp指令应该为非法 |
RVC扩展辅助阅读材料
为方便参考模型的书写,在这里根据20240411版本的手册内容整理了部分指令扩展的思路。
对于RVC指令来说,op = instr(1, 0);funct = instr(15, 13)
op\funct | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
---|---|---|---|---|---|---|---|---|
00 | addi4spn | fld | lw | ld | lbu lhu;lh sb;sh |
fsd | sw | sd |
01 | addi | addiw | li | lui addi16sp zcmop |
ARITHs zcb |
j | beqz | bnez |
10 | slli | fldsp | lwsp | ldsp | jr;mv ebreak jalr;add |
fsdsp | fwsp | sdsp |
在开始阅读各指令的扩展规则时,需要了解一些RVC扩展的前置知识,比如:
rd’, rs1’和rs2’寄存器:受限于16位指令的位宽限制,这几个寄存器只有3位来表示,他们对应到x8~x15寄存器。
op = b'00'
funct = b'000’: ADDI4SPN
该指令将一个0扩展的非0立即数加到栈指针寄存器x2上,并将结果写入rd'
其中,nzuimm[5:4|9:6|2|3]的含义是:
这条指令的第12至11位是立即数的5至4位,第10至7位是立即数的9至6位,第6位是立即数的第2位,第7位是立即数的第3位。
这条指令最终扩展成为addi rd’, x2, nzuimm[9:2]
addi的格式形如:| imm[11:0] | rs1 | 000 | rd | 0010011 |
注意,该指令的立即数为0的时候,不合法。
funct = b'001’: fld
该指令从内存加载一个双精度浮点数到rd’寄存器。
offset的低三位是0,高位进行了0扩展。
这条指令最终扩展成为fld rd′,offset(rs1′)
fld的格式形如: | imm[11:0] | rs1 | 011 | rd | 0000111 |
注意:在昆明湖环境下,该指令要求CSR使能fs.status,也即入参fsIsOff为假。
funct = b'010’: lw
该指令从内存加载一个32位的值到rd’寄存器。
offset的低两位是0,高位进行了0扩展。
这条指令最终扩展成为lw rd′,offset(rs1′)
lw的格式形如: | imm[11:0] | rs1 | 010 | rd | 0000011 |
funct = b'011’: ldsp
该指令从内存加载一个64位的值到rd’寄存器。
offset的低两位是0,高位进行了0扩展。
这条指令最终扩展成为ld rd′,offset(rs1′)
ld的格式形如: | imm[11:0] | rs1 | 011 | rd | 0000011 |
funct = b'100’: zcb extensions 1
在RVC指令中,这部分对应的是zcb扩展中的5条指令:lbu,lhu,lh,sb,sh
在zcb扩展中,进一步地取instr[12:10]作为zcb扩展的指令码,我们记作funct_zcb
funct_zcb = b'000’: lbu
| 100 | 000 | rs1’ | uimm[0|1] | rd’ | 00 |
这个指令从rs1’+uimm的地址读取一字节,用0扩展并并加载到rd’中。
最终翻译为 lb rd’, uimm(rs1')
lb指令的格式形如:| imm[11:0] | rs1 | 000 | rd | 0000011 |
funct_zcb = b'001’, instr[6] =0 : lhu
| 100 | 001 | rs1’ | 0 | uimm[1] | rd’ | 00 |
这个指令从地址rs1’ + uimm读取半word,用0扩展加载到rd’中。
最终翻译为 lhu rd’, uimm(rs1')
lhu指令的格式形如:| imm[11:0] | rs1 | 101 | rd | 0000011 |
funct_zcb = b'001’, instr[6] =1 : lh
| 100 | 001 | rs1’ | 1 | uimm[1] | rd’ | 00 |
这个指令从地址rs1’ + uimm读取半word,符号扩展并加载到rd’中。
最终翻译为 lh rd’, uimm(rs1')
lh指令的格式形如:| imm[11:0] | rs1 | 001 | rd | 0000011 |
funct_zcb = b'010’: sb
| 100 | 010 | rs1’ | uimm[0 | 1] | rd’ | 00 |
这个指令把rs2’的低字节存储到地址rs1’ + uimm指示的内存地址中。
最终翻译为 sb rs2, uimm(rs1')
RVI中sb指令的格式形如:|imm[11:5] | rs2 | rs1 | 000 | imm[4:0] | 0100011 |
funct_zcb = b'011’: sh
| 100 | 011 | rs1’ | 0 | uimm[1] | rd’ | 00 |
这个指令把rs2’的低半字存储到地址rs1’ + uimmz指示的内存地址中。
最终翻译为 sh rd’, uimm(rs1')
sh指令的格式形如:|imm[11:5] | rs2 | rs1 | 001 | imm[4:0] | 0100011 |
funct = b'101’: fsd
fsd将rs2’中的双精度浮点数存储到rs1’ + imm指示的内存区域
该指令的立即数低3位为0,同时进行了0符号扩展。
最终这个指令将被扩展为fsd rs2′, offset(rs1′)
RVI的FSD格式形如:| imm[11:5]| rs2 | rs1 | 011 | imm[4:0] | 0100011 |
注意:在昆明湖环境下,该指令要求CSR使能fs.status,也即入参fsIsOff为假。
funct = b'110’: sw
sw将rs2’中的一个字存储到rs1’ + imm指示的内存区域
该指令的立即数低2位为0,同时进行了0符号扩展。
最终这个指令将被扩展为sw rs2′, offset(rs1′)
RVI的SW格式形如:| imm[11:5]| rs2 | rs1 | 010 | imm[4:0] | 0100011 |
funct = b'111’: sd
fsd将rs2’中的双字存储到rs1’ + imm指示的内存区域
该指令的立即数低3位为0,同时进行了0符号扩展。
最终这个指令将被扩展为sd rs2′, offset(rs1′)
RVI的SD格式形如:| imm[11:5]| rs2 | rs1 | 011 | imm[4:0] | 0100111 |
op = b'01'
funct = b'000’: addi
该指令将一个符号扩展的非0立即数加到rd存储的数字上,并将结果写入rd。
尽管手册规定立即数和rd不为0,但是立即数和rd为0的情况仍可视为合法。前者是HINT指令,而后者是NOP。
这条指令最终扩展成为addi rd, rd, imm
addi的格式形如:| imm[11:0] | rs1 | 000 | rd | 0010011 |
funct = b'001’: addiw
该指令的功能和addi类似,但是先计算得到32位数,然后再符号扩展至64位。
该指令的rd为0时非法。
当立即数不为0时,该指令最终扩展成为addiw, rd, rd, imm
addiw的指令格式为| imm[11:0] | rs1 | 000 | rd | 0011011 |
如果立即数为0,该指令将会扩展成为sext.w rd,不过和addiw的格式是一样的,因此可以将他们归为一类。
funct = b'010’: li
该指令将符号扩展的立即数加载到rd中。
当立即数为0时,该指令为hint,可以看作合法。
这条指令最终扩展成为addi rd, x0, imm
addi的格式形如:| imm[11:0] | rs1 | 000 | rd | 0010011 |
funct = b'011’: lui/addi16sp/zcm
当rd不为0且不为2时,为lui指令,可以扩展为lui rd, imm
lui指令的格式形如: | imm[31:12] | rd | 0110111 |
当rd为0时,为hint,也可当作cli进行译码。
当rd为2时,为addi16sp指令:
扩展为addi x2, x2, nzimm[9:4]
addi的格式形如:| imm[11:0] | rs1 | 000 | rd | 0010011 |
对addi16sp,立即数为0时非法。
此外,当第12至11位皆为0,第7位是1且第6至2位为0时,为zcmop,可以直接翻译为一个不起效的指令,比如与立即数0。
funct = b'100’: arith & zcb extension2
在RVC指令中,这部分对应的是数学运算指令和zcb扩展中的另一部分指令,数学计算指令的对应如下:
其中SRLI64和SRAI64在昆明湖环境下可以不考虑。
srli
当funct2为00时,为srli。
最终可翻译为srli rd′, rd′, 64
srli的格式形如:|0000000|shamt|rs1|101|rd|0010011|
srai
当funct2为01时,为srai。
最终可翻译为srai rd′, rd′, 64
SRAI的格式形如:|0100000|shamt|rs1|101|rd|0010011|
andi
该指令最终扩展为andi rd′, rd′, imm
andi的格式形如|imm[11:0]|rs1|111|rd|0010011|
sub
这条指令最终可以扩展为:sub rd′, rd′, rs2′
sub指令的格式形如:|0100000|rs2|rs1|000|rd|0110011|
xor
这条指令最终可以扩展为:xor rd′, rd′, rs2′
xor指令的格式形如:|0000000|rs2|rs1|100|rd|0110011|
or
这条指令最终可以扩展为:or rd′, rd′, rs2′
or指令的格式形如:|0000000|rs2|rs1|110|rd|0110011|
and
这条指令最终可以扩展为:and rd′, rd′, rs2′
and指令的格式形如:|0000000|rs2|rs1|111|rd|0110011|
subw
这条指令最终可以扩展为:subw rd′, rd′, rs2′
subw指令的格式形如:|0100000|rs2|rs1|000|rd|0111011|
addw
这条指令最终可以扩展为:addw rd′, rd′, rs2′
addw指令的格式形如:|0000000|rs2|rs1|000|rd|0111011|
mul
从mul开始的一部分指令属于zcb扩展。
zcb扩展中,当instr(12, 10) == “111”,且instr(6, 5)为"10"时,为mul指令。
zcb扩展中,当instr(12, 10) == “111”,且instr(6, 5)为"11"时,根据instr(4,2), 共有000的zext.b,001的sext.b,010的zext.h,011的sext.h,100的zext.w和101的not。
该指令可扩展为mul rd, rd, rs2
mul的格式为:|0000001|rs2|rs1|000|rd|0110011|
zext.b
这条指令可以翻译为:andi rd’/rs1’, rd’/rs1’, 0xff
andi的格式形如|imm[11:0]|rs1|111|rd|0010011|
sext.b
该指令翻译为sext.b rd, rd
sext.b指令在RVI下形如:
zext.h
该指令翻译为zext.h rd, rd
zext.h指令在RVI下形如:
sext.h
该指令翻译为sext.h rd, rd
sext.h指令在RVI下形如:
zext.w
该指令等价为add.uw rd’/rs1’, rd’/rs1’, zero
add.uw指令在RVI下形如:
not
该指令等价为xori rd’/rs1’, rd’/rs1’, -1
xori指令在RVI下形如: | imm[11:0] | rs1| 100 | rd | 0010011 |
funct = b'101’: j
最终这个指令将被扩展为jal x0, offset
jal的格式形如:| imm[20|10:1|11|19:12] | rd | 1101111 |
funct = b'110’: beqz
该指令可以扩展到beq rs1‘, x0, offset
beq指令形如: |imm[12|10:5]|rs2|rs1|000|imm[4:1|11]|1100011| imm[12|10:5]rs2rs1001imm[4:1|11]1100011BNE
funct = b'111’: bnez
最终这个指令将被扩展为bne rs1′, x0, offset
bne指令形如:|imm[12|10:5]| rs2 | rs1 | 001 | imm[4:1|11] | 1100011|
op = b'10'
funct = b'000’: slli
该指令将一个符号扩展的非0立即数加到rd存储的数字上,并将结果写入rd。
尽管手册规定立即数和rd不为0,但是立即数和rd为0的情况仍可视为合法。前者是HINT指令,而后者是NOP。
这条指令最终扩展成为slli rd, rd, shamt[5:0]
slli的格式形如:|000000|shamt|rs1|001|rd|0010011|
funct = b'001’: fldsp
该指令最终扩展成为fld rd, offset(x2)
fld的格式形如: | imm[11:0] | rs1 | 011 | rd | 0000111 |
该指令要求CSR使能fs.status
funct = b'010’: lwsp
rd为0时非法。
这条指令最终扩展成为lw rd, offset(x2)
lw的格式形如: | imm[11:0] | rs1 | 010 | rd | 0000011 |
funct = b'011’: ldsp
rd为0时非法。
这条指令最终扩展成为ld rd, offset(x2)
lw的格式形如: | imm[11:0] | rs1 | 011 | rd | 0000011 |
funct = b'100’: jr/mv/ebreak/jalr/add
jr
当rd为0时,非法。
该指令最终可以扩展为jalr x0, 0(rs1)
jalr指令的格式为:|imm[11:0]|rs1|000|rd|1100111|
mv
rd为0时,是hint指令。
该指令最终可以扩展为add rd, x0, rs2
add指令形如:|0000000|rs2|rs1|000|rd|0110011|
ebreak
可以扩展为ebreak指令。
形如:|00000000000100000000000001110011|
jalr
该指令最终可以扩展为jalr x1, 0(rs1)
jalr指令的格式为:|imm[11:0]|rs1|000|rd|1100111|
add
该指令最终可以扩展为add rd, rd, rs2
add指令形如:|0000000|rs2|rs1|000|rd|0110011|
funct = b'101’: fsdsp
这条指令最终扩展成为fsd rs2, offset(x2)
RVI的FSD格式形如:| imm[11:5]| rs2 | rs1 | 011 | imm[4:0] | 0100011 |
该指令要求CSR使能fs.status
funct = b'110’: swsp
这条指令最终扩展成为sw rs2, offset(x2)
RVI的SW格式形如:| imm[11:5]| rs2 | rs1 | 010 | imm[4:0] | 0100011 |
funct = b'111’: sdsp
该指令最终扩展成为sd rd, offset(x2)
RVI的SD格式形如:| imm[11:5]| rs2 | rs1 | 011 | imm[4:0] | 0100111 |