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 |

最后修改 February 22, 2025: ifu top rtl build scripts modify (#76) (5520758)