跳转至

KunmingLake PrunedAddr Documentation

Background Introduction

In the RISC-V manual, B-Type and J-Type instructions are described as follows:

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.

This means that for branch instructions other than jalr, the least significant bit of the jump target must be 0. For the jalr instruction, the manual describes the calculation of the jump target as follows:

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.

This means the least significant bit of the jalr jump target is also 0.

Combining these two parts, we can see that the least significant bit of all PCs must be 0. Therefore, all parts involving PC in the front-end do not need to store the least significant bit, which can save area.

In fact, when the C extension is disabled, the lowest 2 bits of the PC must be 0, otherwise an instruction misalignment exception will be reported.

Usage Guide

The design goal of PrunedAddr is to be as similar to UInt as possible in usage. However, due to Chisel's limitations, this goal cannot be fully realized. In areas where it differs from UInt, it can be compared to Reg or Wire. The specific usage guide is as follows:

  • Use PrunedAddrInit for conversion from UInt to PrunedAddr, for example, val addr1 = PrunedAddrInit(addr2), where the type of addr2 is UInt.
  • Use toUInt for conversion from PrunedAddr to UInt, for example, addr.toUInt.
  • The method def +(offset: UInt) should only be used when offset is an immediate value. For other cases, def +(offset: PrunedAddr) should be used. If offset is a UInt and not an immediate, offset should be converted to PrunedAddr.

Remaining Issues

  • Currently, the use of PrunedAddr is limited to within the front-end; the interface from the front-end to the back-end still uses UInt. Ideally, the back-end should also entirely use PrunedAddr. In this case, the toUInt method should only be used when outputting debugging information.
  • The method def >>(offset: Int) should be deleted to reduce confusion. The corresponding functionality can be achieved by directly selecting the corresponding bits.
  • For the number of pruned bits, the current implementation uses the parameter instOffset. Theoretically, this parameter should change with the switching of the C extension. However, XiangShan currently does not actually support disabling the C extension, and the correctness of disabling the C extension has not been verified.