VexRiscv icon indicating copy to clipboard operation
VexRiscv copied to clipboard

New custom CSR addition

Open davidwilley opened this issue 2 years ago • 15 comments

I modified CustomCsrDemoPlugin and trying to read the value from this CSR register to a variable (line no.13 in the below code snippet) which I am observing in an Oscilloscope. I still see the value 100 in the oscilloscope. Probably I am failing to understand the logic here. What mistake am I doing here?

  1.   CsrVal  = out UInt(32 bits) setName("CsrVal" )        
    
  2.     pipeline plug new Area{
    
  3.        val instructionCounter = Reg(UInt(32 bits))
    
  4.        val cycleCounter = Reg(UInt(32 bits))
    
  5.       CsrVal := 100
    
  6.        cycleCounter := cycleCounter + 1
    
  7.        when(writeBack.arbitration.isFiring) {
    
  8.          instructionCounter := instructionCounter + 1
    
  9.        }
    
  10.        val csrService = pipeline.service(classOf[CsrInterface])
    
  11.        csrService.w(0xB04, instructionCounter)
    
  12.        //csrService.r(0xB05, cycleCounter)
    
  13.        csrService.r(0xB04, CsrVal)
    
  14.        csrService.onWrite(0xB06){
    
  15.          instructionCounter := 0
    
  16.        }
    
  17.        csrService.onRead(0xB07){
    
  18.          instructionCounter := 0x40000000
    
  19.        }
    

davidwilley avatar Apr 11 '22 22:04 davidwilley

Hi,

For the core snipped, you can do

```scala your code here <3 ```

In your code, you define CsrVal as a output, assign it each cycle to 100, and make it readable from the CSR.

So instead i think what you wanted is :

val CsrVal = out UInt(32 bits).setName("CsrVal")
CsrVal := instructionCounter
csrService.r(0xB04, CsrVal)

?

the csrService do not make any link between the .r and .w, they can be completly decoupled hardware things.

Dolu1990 avatar Apr 13 '22 09:04 Dolu1990

Hi, Thank you for the reply. In the program, I am trying to load the instructionCounter value to the newly added CSR using csrService.w(0xB04, instructionCounter). I am assuming this will load instructionCounter value to CSR register at 0xB04.

Then I am trying to read the CSR register value using csrService.r(0xB04, CsrVal). Here I am assuming the value in the CSR register at 0xB04 will be loaded to CsrVal. I am monitoring the CsrVal in oscilloscope.

Is my understanding correct on usage of csrService.r and csrService.w functions?

davidwilley avatar Apr 19 '22 10:04 davidwilley

Ahhhhh, got it now.

csrService.r(0xB04, CsrVal) This will only specify that if the CPU do a CSR read on 0xb04, he will write the CsrVal into the register file. It doesn't assign CsrVal with anything.

csrService.X are only there to specify CPU accesses

Dolu1990 avatar Apr 20 '22 15:04 Dolu1990

Ok, I got it now! Thank you very much. Is there a way that I can read and write CSR registers without CPU intervention?

davidwilley avatar Apr 21 '22 08:04 davidwilley

sure sure,

See how the instruction counter is handled in that demo : https://github.com/SpinalHDL/VexRiscv/blob/master/src/main/scala/vexriscv/demo/CustomCsrDemoPlugin.scala#L17

Dolu1990 avatar Apr 25 '22 09:04 Dolu1990

Hi @Dolu1990 ,

Thanks for the reference. I can now add a CSR and modify it from the software. I am trying to compare program counter value with CSR value to implement some functionality. Can you please provide me some information on how I can get the current program counter value in CustomCsrDemoPlugin class.

davidwilley avatar Jul 25 '22 13:07 davidwilley

Hello @Dolu1990 , It would be nice if you can help me here. I tried calling some classes to fetch program counter value. But nothing worked so far.

davidwilley avatar Jul 28 '22 11:07 davidwilley

Hi I'm in vacancy for the next 6 days, will have some delay

Dolu1990 avatar Jul 28 '22 14:07 Dolu1990

Ah Ok! I will wait for your response then. Thank you!

davidwilley avatar Jul 28 '22 17:07 davidwilley

Can you please provide me some information on how I can get the current program counter value in CustomCsrDemoPlugin class.

So you can get the program counter in a given stage via aGivenStage.input(PC)

Note that this PC value is only valid if the aGivenStage.arbitration.isValid

Dolu1990 avatar Aug 03 '22 07:08 Dolu1990

@Dolu1990 -Thank you for the hint. I am new to this and if I have understood this correctly, you are talking about setup and build stage. Currently I am working in build stage. So I tried build.input(PC) which throws the error "can not resolve symbol input".

I tried execute.input(PC) and there seems to be no error here. But not really sure what's the meaning of stage. Could you please elaborate a bit on the stage and is execute.input(PC) is the correct way to get PC value in the below code ?

class CustomCsrDemoPlugin extends Plugin[VexRiscv]{
  override def build(pipeline: VexRiscv): Unit = {
    import pipeline._
    import pipeline.config._

    pipeline plug new Area{
      val instructionCounter = Reg(UInt(32 bits))
      val cycleCounter = Reg(UInt(32 bits))

      cycleCounter := cycleCounter + 1
      when(writeBack.arbitration.isFiring) {
        instructionCounter := instructionCounter + 1
      }

      val csrService = pipeline.service(classOf[CsrInterface])
      csrService.rw(0xB04, instructionCounter)
      csrService.r(0xB05, cycleCounter)
      csrService.onWrite(0xB06){
        instructionCounter := 0
      }
      csrService.onRead(0xB07){
        instructionCounter := 0x40000000
      }
	  execute.input(PC)// is this correct?
    }
  }
}

davidwilley avatar Aug 03 '22 14:08 davidwilley

if you want to use the PC while a CSR instruction is executing, then yes, execute stage is the righe one, CSR instruction are executing in that specific stage.

execute.input(PC) is good, but what do you want to do with it ?

Dolu1990 avatar Aug 05 '22 09:08 Dolu1990

to figure out the programm counter of a given c code line, you need to check the disassembly of your code (.asm)

also, the linkerscript is configured to start at 0x80000000, where there is some memory, that's why it is already so big.

Dolu1990 avatar Aug 08 '22 08:08 Dolu1990

Hi @Dolu1990 - We are doing something similar to this. But we want to know when the instruction pointed by program counter reaches execution phase in the pipeline. As soon as this instruction reaches execution phase we would trigger a timer as external hardware. So how can we know if an instruction pointed by PC reaches execution phase? Thanks!

nithinrn avatar Sep 06 '22 12:09 nithinrn

@nithinrn Hmm i think trigerring on a instrution reaching execution phase should be checked in the last stage of the CPU (writeback) If checked in the execute stage, there is the chances that the instruction will get canceled by a misspredicted branch / memory load miss.

So, for instance :

    val csr = pipeline plug new Area {
      val csrService = pipeline.service(classOf[CsrInterface])
      val startTrigger = Reg(UInt(32 bits))

      csrService.w(0xBF1, startTrigger)
    }

    writeBack plug new Area {
      import writeBack._
      val startTimer = arbitration.isFiring && input(PC) === triggerA
    }

Dolu1990 avatar Sep 06 '22 12:09 Dolu1990