跳转至

昆明湖 PrunedAddr 文档

背景介绍

在 RISC-V 手册中,对于 B-Type 和 J-Type 的指令描述如下:

The only difference between the S and B formats is that the 12-bit immediate field is used to encode branch offsets in multiples of 2 in the B format. Instead of shifting all bits in the instruction-encoded immediate left by one in hardware as is conventionally done, the middle bits (imm[10:1]) and sign bit stay in fixed positions, while the lowest bit in S format (inst[7]) encodes a high-order bit in B format.

Similarly, the only difference between the U and J formats is that the 20-bit immediate is shifted left by 12 bits to form U immediates and by 1 bit to form J immediates. The location of instruction bits in the U and J format immediates is chosen to maximize overlap with the other formats and with each other.

这意味着对于除了jalr以外的分支指令,跳转目标的最低为一定为 0。而对于jalr指令,手册中对计算跳转目标的描述如下:

The target address is obtained by adding the sign-extended 12-bit I-immediate to the register rs1, then setting the least-significant bit of the result to zero.

这意味着jalr的跳转目标最低位也为 0。

综合这两部分,我们可以发现所有的 PC 最低为一定为 0。于是,前端所有涉及到 PC 的部分均不用存储最低位,这可以节省面积。

实际上,当 C 扩展关闭时,PC 的低 2 位一定为 0,否则会报指令非对齐异常。

使用指南

PrunedAddr的设计目标是使用起来和UInt尽可能相同。但是,出于 Chisel 的限制,这一目标并不能全部实现。在那些和UInt不同的地方,可以类比RegWire。具体的使用指南如下:

  • 使用PrunedAddrInit进行从UIntPrunedAddr的转换,例如val addr1 = PrunedAddrInit(addr2),其中addr2的类型是UInt
  • 使用toUInt进行从PrunedAddrUInt的转换,例如addr.toUInt
  • def +(offset: UInt)这一方法仅当offset为立即数时才应被使用。对于其他情况,应当使用def +(offset: PrunedAddr)。如果offsetUInt且不是立即数,应当将offset转换为PrunedAddr

遗留问题

  • 目前,对于PrunedAddr的使用仅限于前端内部,前端给后端的接口仍然使用UInt。理想情况下,后端也应当全部使用PrunedAddr。此时toUInt这一方法应当只在输出调试信息时使用
  • def >>(offset: Int)这一方法应当删除以减少混乱。对应的功能可以由直接选择对应位来实现
  • 对于裁剪的位数,目前的实现中使用了instOffset这一参数。理论上来说,这一参数应当会随着 C 扩展的开关发生变化。但现在香山实际上不支持关闭 C 扩展,关闭 C 扩展的正确性还未经过验证