4

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!?

nemanja
  • 75
  • 6
  • 3
    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. – ɹɐʎɯɐʞ Nov 11 '19 at 18:13
  • 2
    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 Nov 11 '19 at 19:42

2 Answers2

3

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
yatsukha
  • 46
  • 3
1

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).

nemanja
  • 75
  • 6
  • What happens if we ask for memory location 31? It's still 5 bits, so that might throw an error... If that's true, than the value n has to be a power of 2, so 32 and 31 is the top memory location, we can't have 31 and 30 as the top memory location. Or am I missing something? – apaj Nov 19 '19 at 11:42
  • I'm not sure what would be in that case, but i think that should throw an error,because we don't have that memory location in our memory Mem . I agree with you that value n has to be a power of two, but i taken n=31 for example because that is the case in rocket-chip code that i posted here. – nemanja Nov 21 '19 at 19:32