4
votes

I'm in the process of learning chisel and scala language and try to analyse some lines of rocket-chip code.Could anyone try to explain me this line? https://github.com/chipsalliance/rocket-chip/blob/54237b5602a273378e3b35307bb47eb1e58cb9fb/src/main/scala/rocket/RocketCore.scala#L957

I understand what log2Up function is doing but don't understand why that log2Up(n)-1 and 0,were passed like "arguments" to addr which is val of type UInt!?

2
This is how you perform bit-slicing in chisel. It calls the apply function on UInt (the variant with with two integer arguments, namely the upper bound and the lower bound) and will basically give you the n least significant bits of addr. - ɹɐʎɯɐʞ
Another tip that might help is that due to register 0 being hardcoded to 0 in the RISC-V ISA, Rocket's register file uses a little trick where it reverses the order of the registers physically compared to the RISC-V spec. x1 is index 31 in rf while x31 is index 0. - Jack Koenig

2 Answers

3
votes

I could not find where UInt was defined, but if I had to guess, UInt is a class that has an apply method. This is a special method that allows us to use a parenthesis operator on an instance of the class.

For example lets say we have a class called Multiply that defines an apply method.

class Multiply {
  def apply(a: Int, b: Int): Int = a * b
}

This allows you to call operator () on any instance of that class. For example:

val mul = new Multiply()
println(mul(5, 6)) // prints 30
1
votes

What i concluded is that we use addr(log2Up(n)-1, 0) to get addres bits starting from zero up to log2Up(n)-1 bit. Lets take an example.

If we made object of class RegFile in this way

val reg = RegFile(31, 10)

First, memory rf is created. Size of that memory is 31 data of type UInt width of 10, starting from 0 up to 30. When we compute log2Up(n)-1 we get 4, and we have something like this: addr(4,0). This gives us last five bits of addr. Like @Jack Koenig said in one of the comment above: "Rocket's register file uses a little trick where it reverses the order of the registers physically compared to the RISC-V", that's why we use ~addr. And at least rf(~addr) gives us back what is in that memory location.

This is implemented in this way to provide adequate memory access. Take a look what whould be if we try to get data from memory location that we don't have in our memory. If method access was called in this way

access(42)

We try to access memory location on 41th place, but we only have 31 memory location(30 is top). 42 binary is 101010. Using what i said above

~addr(log2Up(n)-1,0)

would return us 10101 or 21 in decimal. Because order of registers is reversed this is 10th memory location (we try to access 41th but only have 31, 41 minus 31 is 10).